/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
inventory: {},
gold: 0
});
/****
* Classes
****/
var Candy = Container.expand(function (type, row, col) {
var self = Container.call(this);
self.type = type;
self.row = row;
self.col = col;
self.isSpecial = false;
self.specialType = null;
self.matchCount = 0;
var assetMap = {
'blue': 'blueCandy',
'red': 'redCandy',
'green': 'greenCandy',
'orange': 'orangeCandy',
'purple': 'purpleCandy'
};
var specialAssetMap = {
'blueBomb': 'blueBomb',
'redRocket': 'redRocket',
'greenPentagon': 'greenPentagon',
'orangeLollipop': 'orangeLollipop',
'purpleBerry': 'purpleBerry',
'discoBall': 'discoBall',
'blackHole': 'blackHole',
'supernova': 'supernova',
'expires': 'expires',
'writerpir': 'writerpir',
'vriper': 'vriper',
'converter': 'vriper',
'hourglass': 'hourglass',
'eternal': 'purpleCandy',
'void': 'purpleCandy',
'infiniteVoid': 'purpleCandy',
'warlek': 'ultraSupernova'
};
self.graphics = self.attachAsset(assetMap[type], {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
});
self.makeSpecial = function (specialType) {
self.isSpecial = true;
self.specialType = specialType;
// Stop any existing pattern animations by stopping all tweens on graphics
if (self.graphics) {
tween.stop(self.graphics);
}
self.removeChild(self.graphics);
// Safety check to ensure asset exists in specialAssetMap
var assetId = specialAssetMap[specialType];
if (!assetId) {
// Fallback to a default asset if specialType is not found
assetId = 'purpleCandy';
console.warn('Special type not found in specialAssetMap:', specialType, 'using fallback asset');
}
self.graphics = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
});
};
self.explode = function () {
tween(self, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 0
}, {
duration: 200,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (self.parent) {
self.parent.removeChild(self);
}
}
});
};
return self;
});
var ShootingStar = Container.expand(function () {
var self = Container.call(this);
var star = LK.getAsset('gridLine', {
width: 8,
height: 8,
color: 0xFFFFFF,
shape: 'ellipse',
anchorX: 0.5,
anchorY: 0.5
});
self.addChild(star);
// Set random starting position at top of screen
self.x = Math.random() * 2048;
self.y = -50;
// Set falling speed
self.speed = Math.random() * 5 + 3;
// Add trail effect
self.alpha = 0.9;
self.update = function () {
// Only update position if still visible
if (self.y <= 2732 + 100) {
self.y += self.speed;
}
// Remove when off screen (both vertically and horizontally)
if (self.y > 2732 + 50 || self.x < -100 || self.x > 2148) {
if (self.parent) {
self.parent.removeChild(self);
}
}
};
return self;
});
var StarField = Container.expand(function () {
var self = Container.call(this);
var stars = [];
var numStars = 15; // Further reduced for better performance
var twinkleTimer = 0;
self.twinkle = function (star) {
var targetAlpha = Math.random() * 0.6 + 0.3;
var duration = Math.random() * 4000 + 3000; // Even longer duration
tween(star, {
alpha: targetAlpha
}, {
duration: duration,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Add much longer delay before next twinkle to reduce frequency
LK.setTimeout(function () {
if (star && star.parent) {
// Safety check
self.twinkle(star);
}
}, Math.random() * 5000 + 4000); // Much longer delay
}
});
};
// Create individual stars
for (var i = 0; i < numStars; i++) {
var star = LK.getAsset('gridLine', {
width: Math.random() * 6 + 2,
height: Math.random() * 6 + 2,
color: 0xFFFFFF,
shape: 'ellipse',
anchorX: 0.5,
anchorY: 0.5,
x: Math.random() * 2048,
y: Math.random() * 2732,
alpha: Math.random() * 0.8 + 0.2
});
self.addChild(star);
stars.push(star);
// Start twinkling animation for each star with longer staggered timing
LK.setTimeout(function () {
if (star && star.parent) {
// Safety check
self.twinkle(star);
}
}, i * 500 + Math.random() * 2000); // Much longer stagger times with randomization
}
// Track shooting stars
var shootingStars = [];
// Create shooting star occasionally
self.createShootingStar = function () {
var shootingStar = new ShootingStar();
self.addChild(shootingStar);
shootingStars.push(shootingStar);
};
self.update = function () {
// Reduce update frequency to improve performance
if (LK.ticks % 30 !== 0) return; // Only update every 30 frames (0.5 seconds)
// Clean up shooting stars that are off screen
for (var i = shootingStars.length - 1; i >= 0; i--) {
var star = shootingStars[i];
if (star.y > 2732 + 50 || star.x < -100 || star.x > 2148) {
// Remove from parent to prevent memory leaks
if (star.parent) {
star.parent.removeChild(star);
}
shootingStars.splice(i, 1);
}
}
// Reduce shooting star creation frequency to improve performance
if (Math.random() < 0.005 && shootingStars.length < 3) {
// 0.5% chance per frame, max 3 shooting stars
self.createShootingStar();
}
// Simplified sliding movement with performance optimization
for (var i = 0; i < shootingStars.length; i++) {
var star = shootingStars[i];
// Check if this star should slide (reduced to 20% chance)
if (star.shouldSlide === undefined) {
star.shouldSlide = Math.random() < 0.2; // 20% chance
star.slideDirection = Math.random() * Math.PI * 2; // Random direction
star.slideSpeed = Math.random() * 1 + 0.5; // Reduced slide speed
}
// Apply sliding movement if enabled
if (star.shouldSlide) {
star.x += Math.cos(star.slideDirection) * star.slideSpeed;
// Keep star within screen bounds horizontally
if (star.x < -50 || star.x > 2098) {
star.slideDirection = Math.PI - star.slideDirection; // Reverse horizontal direction
}
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2E1065
});
/****
* Game Code
****/
// Define getRequiredScoreForLevel function in global scope
function getRequiredScoreForLevel(targetLevel) {
if (targetLevel <= 1) return 0;
if (targetLevel === 2) return 50000;
// For levels 3+: 50000 * 4^(level-2)
return 50000 * Math.pow(4, targetLevel - 2);
}
var GRID_SIZE = 8;
var CELL_SIZE = 200;
var GRID_START_X = 224;
var GRID_START_Y = 566;
var COLORS = ['blue', 'red', 'green', 'orange', 'purple'];
var grid = [];
var selectedCandy = null;
var score = 0;
var level = 1;
var gold = 0;
// Reset gold to starting value
storage.gold = gold;
var inventory = {};
// Reset inventory to empty
storage.inventory = inventory;
var isProcessing = false;
var comboMultiplier = 1;
// Secret feature variables
var secretMode = false;
var secretBalls = [];
var secretClickSequence = []; // Track sequence of ball clicks
var secretGridBackup = null; // Backup of original grid state
var onlySpecialCandies = false; // Flag to spawn only special candies
var cascadeComboCount = 0; // Track consecutive cascade combos
var savedComboCount = 0; // Track saved combo count from hourglass
var cascadeComboNames = ['', 'COMBO', 'DOUBLE COMBO', 'BRUTALITY', 'AMAZING', 'SUPERBEAST', 'ULTRA SUPER COMBO', 'PERFECT']; // Combo names for each level
var lastCascadeTime = 0; // Track time of last cascade for timeout
var hourglassCount = 0; // Track number of hourglasses available
var yellowCandiesClicked = []; // Track yellow candies that have been clicked small
// Timeless Karadeniz system variables
var timelessKaradenizCandies = []; // Track all timeless Karadeniz candies
var lastClickTime = 0; // Track last click time for double-click detection
var lastClickedCandy = null; // Track last clicked candy for double-click detection
var DOUBLE_CLICK_THRESHOLD = 500; // Maximum time between clicks for double-click (ms)
// Black hole click tracking for void creation
var blackHoleClickCounts = {}; // key: row_col, value: click count
var voidPositions = []; // Array of {row, col} for voids on the grid
var eternalCandies = []; // Array to track eternal candies on the grid
var selectedEternalCandy = null; // Track selected eternal candy for swapping
// Helper: get key for black hole/void click tracking
function getGridKey(row, col) {
return row + "_" + col;
}
// Helper: create an eternal candy of specific type at a given position
function createEternalCandyOfType(row, col, candyType) {
// Remove any candy at this position
if (grid[row][col] && grid[row][col].parent) {
grid[row][col].parent.removeChild(grid[row][col]);
}
// Create eternal candy with the specified type
var eternalCandy = new Candy(candyType, row, col);
eternalCandy.isSpecial = true;
eternalCandy.specialType = 'eternal';
eternalCandy.type = 'eternal' + candyType.charAt(0).toUpperCase() + candyType.slice(1); // e.g., 'eternalBlue'
eternalCandy.baseType = candyType; // Store original type for combo logic
eternalCandy.canSwapAnywhere = true;
// Replace graphics with eternal look based on candy type
eternalCandy.removeChild(eternalCandy.graphics);
var assetMap = {
'blue': 'blueCandy',
'red': 'redCandy',
'green': 'greenCandy',
'orange': 'orangeCandy',
'purple': 'purpleCandy'
};
eternalCandy.graphics = eternalCandy.attachAsset(assetMap[candyType], {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
});
tween(eternalCandy.graphics, {
tint: 0xFFD700,
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 500,
onFinish: function onFinish() {
// Add continuous golden glow effect
var _pulseEternal = function pulseEternal() {
if (eternalCandy && eternalCandy.parent && eternalCandy.specialType === 'eternal') {
tween(eternalCandy.graphics, {
tint: 0xFFFF00,
scaleX: 1.5,
scaleY: 1.5,
alpha: 0.9
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(eternalCandy.graphics, {
tint: 0xFFD700,
scaleX: 1.3,
scaleY: 1.3,
alpha: 1.0
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
LK.setTimeout(_pulseEternal, 200);
}
});
}
});
}
};
_pulseEternal();
}
});
// Add to grid and game
grid[row][col] = eternalCandy;
gameContainer.addChild(eternalCandy);
// Track eternal candy
eternalCandies.push({
row: row,
col: col
});
}
// Helper: create an eternal candy at a given position
function createEternalCandy(row, col) {
// Remove any candy at this position
if (grid[row][col] && grid[row][col].parent) {
grid[row][col].parent.removeChild(grid[row][col]);
}
// Create eternal candy (special candy with unique properties)
var eternalCandy = new Candy('purple', row, col);
eternalCandy.isSpecial = true;
eternalCandy.specialType = 'eternal';
eternalCandy.type = 'eternal';
eternalCandy.canSwapAnywhere = true;
// Replace graphics with a unique eternal look (golden glowing purple)
eternalCandy.removeChild(eternalCandy.graphics);
eternalCandy.graphics = eternalCandy.attachAsset('purpleCandy', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
});
tween(eternalCandy.graphics, {
tint: 0xFFD700,
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 500,
onFinish: function onFinish() {
// Add continuous golden glow effect
var _pulseEternal = function pulseEternal() {
if (eternalCandy && eternalCandy.parent && eternalCandy.specialType === 'eternal') {
tween(eternalCandy.graphics, {
tint: 0xFFFF00,
scaleX: 1.5,
scaleY: 1.5,
alpha: 0.9
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(eternalCandy.graphics, {
tint: 0xFFD700,
scaleX: 1.3,
scaleY: 1.3,
alpha: 1.0
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
LK.setTimeout(_pulseEternal, 200);
}
});
}
});
}
};
_pulseEternal();
}
});
// Add to grid and game
grid[row][col] = eternalCandy;
gameContainer.addChild(eternalCandy);
// Track eternal candy
eternalCandies.push({
row: row,
col: col
});
// Visual effect
LK.effects.flashScreen(0xFFD700, 1000);
// Show notification
var eternalText = new Text2('EBEDI ŞEKER YARATILDI!', {
size: 90,
fill: '#FFD700'
});
eternalText.anchor.set(0.5, 0.5);
eternalText.x = 1024;
eternalText.y = 1366;
eternalText.alpha = 0;
game.addChild(eternalText);
tween(eternalText, {
alpha: 1,
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 500,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(eternalText, {
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
if (eternalText.parent) eternalText.parent.removeChild(eternalText);
}
});
}, 1500);
}
});
}
// Helper: check if a candy is eternal
function isEternalCandy(candy) {
return candy && candy.isSpecial && candy.specialType === 'eternal';
}
// Helper: handle eternal candy swapping with any candy on the map
function handleEternalCandySwap(eternalCandy, targetCandy) {
if (!eternalCandy || !targetCandy || eternalCandy === targetCandy) return false;
var eternalRow = eternalCandy.row;
var eternalCol = eternalCandy.col;
var targetRow = targetCandy.row;
var targetCol = targetCandy.col;
// Swap positions in grid
grid[eternalRow][eternalCol] = targetCandy;
grid[targetRow][targetCol] = eternalCandy;
// Update candy properties
eternalCandy.row = targetRow;
eternalCandy.col = targetCol;
targetCandy.row = eternalRow;
targetCandy.col = eternalCol;
// Animate the swap with spectacular effect
tween(eternalCandy, {
x: GRID_START_X + targetCol * CELL_SIZE + CELL_SIZE / 2,
y: GRID_START_Y + targetRow * CELL_SIZE + CELL_SIZE / 2,
scaleX: 1.5,
scaleY: 1.5,
tint: 0xFFFFFF
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(eternalCandy, {
scaleX: 1.3,
scaleY: 1.3,
tint: 0xFFD700
}, {
duration: 200,
easing: tween.easeOut
});
}
});
tween(targetCandy, {
x: GRID_START_X + eternalCol * CELL_SIZE + CELL_SIZE / 2,
y: GRID_START_Y + eternalRow * CELL_SIZE + CELL_SIZE / 2
}, {
duration: 300,
easing: tween.easeOut
});
// Update eternal candy position tracking
for (var i = 0; i < eternalCandies.length; i++) {
if (eternalCandies[i].row === eternalRow && eternalCandies[i].col === eternalCol) {
eternalCandies[i].row = targetRow;
eternalCandies[i].col = targetCol;
break;
}
}
// Create swap effect
LK.effects.flashScreen(0xFFD700, 500);
return true;
}
// Helper: create a void at a given position
function createVoidAt(row, col) {
// Remove any candy at this position
if (grid[row][col] && grid[row][col].parent) {
grid[row][col].parent.removeChild(grid[row][col]);
}
// Create a void object (special candy with type 'void')
var voidCandy = new Candy('purple', row, col);
voidCandy.isSpecial = true;
voidCandy.specialType = 'void';
voidCandy.type = 'void';
voidCandy.voidComboType = null; // Will be set on first combo
voidCandy.voidComboActive = false;
// Replace graphics with a unique void look (purpleCandy with special tint)
voidCandy.removeChild(voidCandy.graphics);
voidCandy.graphics = voidCandy.attachAsset('purpleCandy', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
});
tween(voidCandy.graphics, {
tint: 0x6e00ff,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 400,
onFinish: function onFinish() {
tween(voidCandy.graphics, {
tint: 0x9013fe,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 300
});
}
});
// Add to grid and game
grid[row][col] = voidCandy;
gameContainer.addChild(voidCandy);
// Track void position
voidPositions.push({
row: row,
col: col
});
}
// Helper: check if a candy is a void
function isVoidCandy(candy) {
return candy && candy.isSpecial && candy.specialType === 'void';
}
// Helper: get all void candies on the grid
function getAllVoidCandies() {
var result = [];
for (var i = 0; i < voidPositions.length; i++) {
var pos = voidPositions[i];
if (grid[pos.row][pos.col] && isVoidCandy(grid[pos.row][pos.col])) {
result.push(grid[pos.row][pos.col]);
}
}
return result;
}
// Helper: clear all voids from the grid and voidPositions
function clearAllVoids() {
for (var i = 0; i < voidPositions.length; i++) {
var pos = voidPositions[i];
if (grid[pos.row][pos.col] && grid[pos.row][pos.col].parent) {
grid[pos.row][pos.col].parent.removeChild(grid[pos.row][pos.col]);
}
grid[pos.row][pos.col] = null;
}
voidPositions = [];
}
// Helper: handle timeless black hole combo logic - NEW FUNCTIONALITY
function handleTimelessBlackHoleCombo(matchArr) {
// Find if any timeless black hole is in this match
var timelessBlackHole = null;
for (var i = 0; i < matchArr.length; i++) {
if (matchArr[i] && matchArr[i].isSpecial && matchArr[i].specialType === 'expires' && matchArr[i].isTimeless) {
timelessBlackHole = matchArr[i];
break;
}
}
if (!timelessBlackHole) return false;
// NEW FUNCTIONALITY PLACEHOLDER - Add your desired behavior here
// For now, just show a message that functionality is being changed
var changeText = new Text2('ZAMANSIZ KARA DELİK İŞLEVİ DEĞİŞTİRİLİYOR...', {
size: 80,
fill: '#FF0000'
});
changeText.anchor.set(0.5, 0.5);
changeText.x = 1024;
changeText.y = 1366;
changeText.alpha = 0;
game.addChild(changeText);
tween(changeText, {
alpha: 1,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 400,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(changeText, {
alpha: 0
}, {
duration: 400,
onFinish: function onFinish() {
if (changeText.parent) changeText.parent.removeChild(changeText);
}
});
}, 1200);
}
});
// Remove the timeless black hole for now
grid[timelessBlackHole.row][timelessBlackHole.col] = null;
timelessBlackHole.explode();
return true;
}
// Helper: handle void combo logic
function handleVoidCombo(matchArr) {
// Find if any void is in this match
var voidCandy = null;
var infiniteVoidCandy = null;
for (var i = 0; i < matchArr.length; i++) {
if (isVoidCandy(matchArr[i])) {
voidCandy = matchArr[i];
// Check if this is an infinite void (enhanced void with special property)
if (matchArr[i].isInfiniteVoid) {
infiniteVoidCandy = matchArr[i];
}
break;
}
}
if (!voidCandy) return false;
// Check for infinite void + purple candy combo first
if (infiniteVoidCandy) {
var purpleCandy = null;
for (var i = 0; i < matchArr.length; i++) {
if (matchArr[i] !== infiniteVoidCandy && matchArr[i].type === 'purple' && !matchArr[i].isSpecial) {
purpleCandy = matchArr[i];
break;
}
}
if (purpleCandy) {
// Create eternal candy at infinite void position
createEternalCandy(infiniteVoidCandy.row, infiniteVoidCandy.col);
// Remove purple candy
grid[purpleCandy.row][purpleCandy.col] = null;
purpleCandy.explode();
// Remove infinite void
grid[infiniteVoidCandy.row][infiniteVoidCandy.col] = null;
infiniteVoidCandy.explode();
return true;
}
}
// Find the type of candy being comboed with void
var comboType = null;
for (var i = 0; i < matchArr.length; i++) {
if (matchArr[i] !== voidCandy && !isVoidCandy(matchArr[i])) {
comboType = matchArr[i].type;
break;
}
}
if (!comboType) return false;
// Transform all candies of comboType on the map to void
for (var row = 0; row < GRID_SIZE; row++) {
for (var col = 0; col < GRID_SIZE; col++) {
var c = grid[row][col];
if (c && c.type === comboType && !isVoidCandy(c)) {
createVoidAt(row, col);
}
}
}
// Trigger 4x4 attraction effect for the original void
LK.setTimeout(function () {
triggerVoid4x4Attraction(voidCandy);
}, 500);
// Visual effect
LK.effects.flashScreen(0x6e00ff, 800);
// Show notification
var voidText = new Text2('VOID CONSUMES ALL ' + comboType.toUpperCase() + '!', {
size: 80,
fill: '#6e00ff'
});
voidText.anchor.set(0.5, 0.5);
voidText.x = 1024;
voidText.y = 1366;
voidText.alpha = 0;
game.addChild(voidText);
tween(voidText, {
alpha: 1,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 400,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(voidText, {
alpha: 0
}, {
duration: 400,
onFinish: function onFinish() {
if (voidText.parent) voidText.parent.removeChild(voidText);
}
});
}, 1200);
}
});
return true;
}
// Helper: trigger eternal candy 6x6 attraction with 80% bonus
function triggerEternal6x6Attraction(eternalCandy) {
if (!eternalCandy || !eternalCandy.parent) return;
var centerRow = eternalCandy.row;
var centerCol = eternalCandy.col;
// Collect all candies in 6x6 area around eternal candy (3 cells in each direction)
var attractedCandies = [];
for (var r = Math.max(0, centerRow - 3); r <= Math.min(GRID_SIZE - 1, centerRow + 3); r++) {
for (var c = Math.max(0, centerCol - 3); c <= Math.min(GRID_SIZE - 1, centerCol + 3); c++) {
if (grid[r][c] && grid[r][c] !== eternalCandy) {
attractedCandies.push(grid[r][c]);
grid[r][c] = null; // Remove from grid immediately
}
}
}
// Animate attraction of candies to eternal candy
for (var i = 0; i < attractedCandies.length; i++) {
(function (targetCandy, index) {
if (targetCandy && targetCandy.parent) {
// Animate candy moving to eternal candy
tween(targetCandy, {
x: eternalCandy.x,
y: eternalCandy.y,
scaleX: 0.2,
scaleY: 0.2,
alpha: 0.8
}, {
duration: 900 + index * 40,
easing: tween.easeIn,
onFinish: function onFinish() {
if (targetCandy && targetCandy.parent) {
// Explode with 80% bonus store points
var bonusScore = Math.floor(15 * comboMultiplier * 1.8);
var bonusGold = Math.floor(8 * 1.8);
if (comboMultiplier > 1) {
bonusGold += Math.floor(10 * 1.8);
}
score += bonusScore;
gold += bonusGold;
targetCandy.explode();
}
}
});
}
})(attractedCandies[i], i);
}
// Create visual eternal implosion effect
tween(eternalCandy.graphics, {
scaleX: 3.0,
scaleY: 3.0,
alpha: 0.4,
rotation: Math.PI * 6
}, {
duration: 1400,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Massive explosion after attraction
LK.effects.flashScreen(0xFFD700, 1200);
// Add score bonus for eternal activation
score += Math.floor(35000 * 1.8);
gold += Math.floor(17500 * 1.8);
updateUI();
// Clean up the eternal candy
if (eternalCandy && eternalCandy.parent) {
eternalCandy.parent.removeChild(eternalCandy);
}
grid[centerRow][centerCol] = null;
// Remove from eternal positions
for (var i = 0; i < eternalCandies.length; i++) {
if (eternalCandies[i].row === centerRow && eternalCandies[i].col === centerCol) {
eternalCandies.splice(i, 1);
break;
}
}
// Drop new candies after explosion
LK.setTimeout(function () {
dropCandies();
LK.setTimeout(function () {
processMatches();
}, 300);
}, 500);
}
});
}
// Helper: trigger void attraction and explosion in 4x4 area with 60% bonus
function triggerVoid4x4Attraction(voidCandy) {
if (!voidCandy || !voidCandy.parent) return;
var centerRow = voidCandy.row;
var centerCol = voidCandy.col;
// Collect all candies in 4x4 area around void (2 cells in each direction)
var attractedCandies = [];
for (var r = Math.max(0, centerRow - 2); r <= Math.min(GRID_SIZE - 1, centerRow + 2); r++) {
for (var c = Math.max(0, centerCol - 2); c <= Math.min(GRID_SIZE - 1, centerCol + 2); c++) {
if (grid[r][c] && grid[r][c] !== voidCandy) {
attractedCandies.push(grid[r][c]);
grid[r][c] = null; // Remove from grid immediately
}
}
}
// Animate attraction of candies to void
for (var i = 0; i < attractedCandies.length; i++) {
(function (targetCandy, index) {
if (targetCandy && targetCandy.parent) {
// Animate candy moving to void
tween(targetCandy, {
x: voidCandy.x,
y: voidCandy.y,
scaleX: 0.3,
scaleY: 0.3,
alpha: 0.7
}, {
duration: 800 + index * 50,
easing: tween.easeIn,
onFinish: function onFinish() {
if (targetCandy && targetCandy.parent) {
// Explode with 60% bonus store points
var bonusScore = Math.floor(15 * comboMultiplier * 1.6);
var bonusGold = Math.floor(8 * 1.6);
if (comboMultiplier > 1) {
bonusGold += Math.floor(10 * 1.6);
}
score += bonusScore;
gold += bonusGold;
targetCandy.explode();
}
}
});
}
})(attractedCandies[i], i);
}
// Create visual void implosion effect
tween(voidCandy.graphics, {
scaleX: 2.5,
scaleY: 2.5,
alpha: 0.5,
rotation: Math.PI * 4
}, {
duration: 1200,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Massive explosion after attraction
LK.effects.flashScreen(0x6e00ff, 1000);
// Add score bonus for void activation
score += Math.floor(25000 * 1.6);
gold += Math.floor(12500 * 1.6);
updateUI();
// Clean up the void
if (voidCandy && voidCandy.parent) {
voidCandy.parent.removeChild(voidCandy);
}
grid[centerRow][centerCol] = null;
// Remove from void positions
for (var i = 0; i < voidPositions.length; i++) {
if (voidPositions[i].row === centerRow && voidPositions[i].col === centerCol) {
voidPositions.splice(i, 1);
break;
}
}
// Drop new candies after explosion
LK.setTimeout(function () {
dropCandies();
LK.setTimeout(function () {
processMatches();
}, 300);
}, 500);
}
});
}
// Helper: trigger void attraction and explosion in 3x3 area
function triggerVoidAttraction() {
// Find all void candies
var allVoids = getAllVoidCandies();
if (allVoids.length === 0) return;
// Choose a central void as the attraction point
var centralVoid = allVoids[Math.floor(allVoids.length / 2)];
var centerRow = centralVoid.row;
var centerCol = centralVoid.col;
// Collect all candies in 3x3 area around central void
var attractedCandies = [];
for (var r = Math.max(0, centerRow - 1); r <= Math.min(GRID_SIZE - 1, centerRow + 1); r++) {
for (var c = Math.max(0, centerCol - 1); c <= Math.min(GRID_SIZE - 1, centerCol + 1); c++) {
if (grid[r][c] && grid[r][c] !== centralVoid) {
attractedCandies.push(grid[r][c]);
grid[r][c] = null; // Remove from grid immediately
}
}
}
// Animate attraction of candies to central void
for (var i = 0; i < attractedCandies.length; i++) {
(function (targetCandy, index) {
if (targetCandy && targetCandy.parent) {
// Animate candy moving to central void
tween(targetCandy, {
x: centralVoid.x,
y: centralVoid.y,
scaleX: 0.3,
scaleY: 0.3,
alpha: 0.7
}, {
duration: 800 + index * 50,
easing: tween.easeIn,
onFinish: function onFinish() {
if (targetCandy && targetCandy.parent) {
explodeCandyWithScore(targetCandy);
}
}
});
}
})(attractedCandies[i], i);
}
// Create visual void implosion effect
tween(centralVoid.graphics, {
scaleX: 2.5,
scaleY: 2.5,
alpha: 0.5,
rotation: Math.PI * 4
}, {
duration: 1200,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Massive explosion after attraction
LK.effects.flashScreen(0x6e00ff, 1000);
// Add score bonus
score += 25000;
gold += 12500;
updateUI();
// Clean up the central void
if (centralVoid && centralVoid.parent) {
centralVoid.parent.removeChild(centralVoid);
}
grid[centerRow][centerCol] = null;
// Remove from void positions
for (var i = 0; i < voidPositions.length; i++) {
if (voidPositions[i].row === centerRow && voidPositions[i].col === centerCol) {
voidPositions.splice(i, 1);
break;
}
}
// Drop new candies after explosion
LK.setTimeout(function () {
dropCandies();
LK.setTimeout(function () {
processMatches();
}, 300);
}, 500);
}
});
}
// Helper: handle 4-void combo (map clear)
function handleFourVoidCombo(matchArr) {
// Check if all are voids and length is 4
if (matchArr.length === 4 && matchArr.every(isVoidCandy)) {
// Clear the entire map
for (var row = 0; row < GRID_SIZE; row++) {
for (var col = 0; col < GRID_SIZE; col++) {
if (grid[row][col] && grid[row][col].parent) {
grid[row][col].parent.removeChild(grid[row][col]);
}
grid[row][col] = null;
}
}
clearAllVoids();
// Add massive store points
score += 8474477;
gold += 8474477;
updateUI();
// Visual effect
LK.effects.flashScreen(0x6e00ff, 2000);
var voidText = new Text2('VOID APOCALYPSE! +8474477', {
size: 120,
fill: '#6e00ff'
});
voidText.anchor.set(0.5, 0.5);
voidText.x = 1024;
voidText.y = 1366;
voidText.alpha = 0;
game.addChild(voidText);
tween(voidText, {
alpha: 1,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 800,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(voidText, {
alpha: 0
}, {
duration: 800,
onFinish: function onFinish() {
if (voidText.parent) voidText.parent.removeChild(voidText);
}
});
}, 2000);
}
});
return true;
}
return false;
}
// Main menu system variables
var gameState = 'menu'; // 'menu', 'playing', 'settings'
var mainMenuContainer = null;
var settingsMenuContainer = null;
var statisticsMenuContainer = null;
var gameContainer = null;
// Achievement system variables
var achievements = {
smallCollector: false,
hiddenStars: false,
leagues: false,
universe: false
};
var ballsClickedSmall = []; // Track which balls have been clicked to small size
var totalBallsToClick = 0; // Total number of balls that need to be clicked small
// Hidden Stars achievement variables
var hiddenStarsSequence = []; // Track the sequence entered after clicking shooting star
var hiddenStarsActivated = false; // Track if shooting star was clicked
// Save system variables
var saveButtonPressed = false;
var gameStateSaved = false;
var savesMenuContainer = null;
var savesMenuMode = 'save'; // 'save' or 'load'
// Create animated starfield background
var starField = new StarField();
game.addChild(starField);
// Create main menu
function createMainMenu() {
mainMenuContainer = new Container();
game.addChild(mainMenuContainer);
// Game title
var titleText = new Text2('ŞEKERLERI PATLAT', {
size: 140,
fill: '#FFD700'
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 800;
mainMenuContainer.addChild(titleText);
// Start Game button
var startButton = LK.getAsset('progressBarBg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.0,
scaleY: 1.5
});
startButton.x = 1024;
startButton.y = 1200;
mainMenuContainer.addChild(startButton);
var startButtonText = new Text2('OYUNA BAŞLA', {
size: 80,
fill: '#FFFFFF'
});
startButtonText.anchor.set(0.5, 0.5);
startButtonText.x = 1024;
startButtonText.y = 1200;
mainMenuContainer.addChild(startButtonText);
// Settings button
var settingsButton = LK.getAsset('progressBarBg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.0,
scaleY: 1.5
});
settingsButton.x = 1024;
settingsButton.y = 1500;
mainMenuContainer.addChild(settingsButton);
var settingsButtonText = new Text2('AYARLAR', {
size: 80,
fill: '#FFFFFF'
});
settingsButtonText.anchor.set(0.5, 0.5);
settingsButtonText.x = 1024;
settingsButtonText.y = 1500;
mainMenuContainer.addChild(settingsButtonText);
// Statistics button
var statisticsButton = LK.getAsset('progressBarBg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.0,
scaleY: 1.5
});
statisticsButton.x = 1024;
statisticsButton.y = 1800;
mainMenuContainer.addChild(statisticsButton);
var statisticsButtonText = new Text2('İSTATİSTİKLER', {
size: 80,
fill: '#FFFFFF'
});
statisticsButtonText.anchor.set(0.5, 0.5);
statisticsButtonText.x = 1024;
statisticsButtonText.y = 1800;
mainMenuContainer.addChild(statisticsButtonText);
// New Game button
var newGameButton = LK.getAsset('progressBarBg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.0,
scaleY: 1.5
});
newGameButton.x = 1024;
newGameButton.y = 2100;
mainMenuContainer.addChild(newGameButton);
var newGameButtonText = new Text2('YENİ OYUN', {
size: 80,
fill: '#FFFFFF'
});
newGameButtonText.anchor.set(0.5, 0.5);
newGameButtonText.x = 1024;
newGameButtonText.y = 2100;
mainMenuContainer.addChild(newGameButtonText);
// Saves button
var savesButton = LK.getAsset('progressBarBg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.0,
scaleY: 1.5
});
savesButton.x = 1024;
savesButton.y = 2400;
mainMenuContainer.addChild(savesButton);
var savesButtonText = new Text2('KAYITLAR', {
size: 80,
fill: '#FFFFFF'
});
savesButtonText.anchor.set(0.5, 0.5);
savesButtonText.x = 1024;
savesButtonText.y = 2400;
mainMenuContainer.addChild(savesButtonText);
// Store button references for click detection
mainMenuContainer.startButton = startButton;
mainMenuContainer.settingsButton = settingsButton;
mainMenuContainer.statisticsButton = statisticsButton;
mainMenuContainer.newGameButton = newGameButton;
mainMenuContainer.savesButton = savesButton;
}
// Create saves menu
function createSavesMenu() {
savesMenuContainer = new Container();
game.addChild(savesMenuContainer);
savesMenuContainer.alpha = 0;
// Saves title - changes based on mode
var titleText = savesMenuMode === 'load' ? 'KAYIT SEÇİN' : 'KAYITLAR';
var savesTitle = new Text2(titleText, {
size: 120,
fill: '#FFD700'
});
savesTitle.anchor.set(0.5, 0.5);
savesTitle.x = 1024;
savesTitle.y = 400;
savesMenuContainer.addChild(savesTitle);
// Create 4 save slots arranged in 2x2 grid
var saveSlots = [];
var slotPositions = [{
x: 650,
y: 800
},
// Top left
{
x: 1398,
y: 800
},
// Top right
{
x: 650,
y: 1400
},
// Bottom left
{
x: 1398,
y: 1400
} // Bottom right
];
for (var i = 0; i < 4; i++) {
// Create save slot background
var slotBg = LK.getAsset('progressBarBg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.8,
scaleY: 2.5
});
slotBg.x = slotPositions[i].x;
slotBg.y = slotPositions[i].y;
savesMenuContainer.addChild(slotBg);
// Check if there's a saved game for this slot
var slotPrefix = 'saveSlot' + (i + 1) + '_';
var hasSave = storage[slotPrefix + 'hasSave'];
var slotText = '';
var scoreText = '';
var levelText = '';
if (hasSave) {
// Slot has saved data
slotText = 'Slot ' + (i + 1);
scoreText = 'Score: ' + (storage[slotPrefix + 'score'] || 0);
levelText = 'Level: ' + (storage[slotPrefix + 'level'] || 1);
} else {
// Empty slot
slotText = 'Slot ' + (i + 1);
scoreText = 'Empty';
levelText = '';
}
// Slot number text
var slotNumberText = new Text2(slotText, {
size: 60,
fill: '#FFD700'
});
slotNumberText.anchor.set(0.5, 0.5);
slotNumberText.x = slotPositions[i].x;
slotNumberText.y = slotPositions[i].y - 80;
savesMenuContainer.addChild(slotNumberText);
// Score text
var slotScoreText = new Text2(scoreText, {
size: 50,
fill: '#FFFFFF'
});
slotScoreText.anchor.set(0.5, 0.5);
slotScoreText.x = slotPositions[i].x;
slotScoreText.y = slotPositions[i].y - 20;
savesMenuContainer.addChild(slotScoreText);
// Level text
if (levelText) {
var slotLevelText = new Text2(levelText, {
size: 50,
fill: '#FFFFFF'
});
slotLevelText.anchor.set(0.5, 0.5);
slotLevelText.x = slotPositions[i].x;
slotLevelText.y = slotPositions[i].y + 40;
savesMenuContainer.addChild(slotLevelText);
}
// Store slot data for click detection
saveSlots.push({
background: slotBg,
slotIndex: i,
x: slotPositions[i].x,
y: slotPositions[i].y,
hasSave: !!hasSave
});
}
// Back button
var backButton = LK.getAsset('progressBarBg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.2
});
backButton.x = 1024;
backButton.y = 1800;
savesMenuContainer.addChild(backButton);
var backButtonText = new Text2('GERİ', {
size: 70,
fill: '#FFFFFF'
});
backButtonText.anchor.set(0.5, 0.5);
backButtonText.x = 1024;
backButtonText.y = 1800;
savesMenuContainer.addChild(backButtonText);
// Store button and slots references for click detection
savesMenuContainer.backButton = backButton;
savesMenuContainer.saveSlots = saveSlots;
}
// Create statistics menu
function createStatisticsMenu() {
statisticsMenuContainer = new Container();
game.addChild(statisticsMenuContainer);
statisticsMenuContainer.alpha = 0;
// Statistics title
var statisticsTitle = new Text2('İSTATİSTİKLER', {
size: 120,
fill: '#FFD700'
});
statisticsTitle.anchor.set(0.5, 0.5);
statisticsTitle.x = 1024;
statisticsTitle.y = 400;
statisticsMenuContainer.addChild(statisticsTitle);
// Get statistics from storage
var highestScore = storage.highestScore || 0;
var highestLevel = storage.highestLevel || 1;
var totalGold = storage.totalGoldEarned || 0;
var gamesPlayed = storage.gamesPlayed || 0;
var achievementsUnlocked = 0;
// Count achievements
if (storage.smallCollectorAchieved) achievementsUnlocked++;
if (storage.hiddenStarsAchieved) achievementsUnlocked++;
if (storage.leaguesAchieved) achievementsUnlocked++;
if (storage.universeAchieved) achievementsUnlocked++;
// Display statistics
var yPosition = 600;
var spacing = 120;
// Highest Score
var scoreStatText = new Text2('En Yüksek Skor: ' + highestScore, {
size: 60,
fill: '#FFFFFF'
});
scoreStatText.anchor.set(0.5, 0.5);
scoreStatText.x = 1024;
scoreStatText.y = yPosition;
statisticsMenuContainer.addChild(scoreStatText);
// Highest Level
var levelStatText = new Text2('En Yüksek Seviye: ' + highestLevel, {
size: 60,
fill: '#FFFFFF'
});
levelStatText.anchor.set(0.5, 0.5);
levelStatText.x = 1024;
levelStatText.y = yPosition + spacing;
statisticsMenuContainer.addChild(levelStatText);
// Total Gold
var goldStatText = new Text2('Toplam Altın: ' + totalGold, {
size: 60,
fill: '#FFD700'
});
goldStatText.anchor.set(0.5, 0.5);
goldStatText.x = 1024;
goldStatText.y = yPosition + spacing * 2;
statisticsMenuContainer.addChild(goldStatText);
// Games Played
var gamesStatText = new Text2('Oynanan Oyunlar: ' + gamesPlayed, {
size: 60,
fill: '#FFFFFF'
});
gamesStatText.anchor.set(0.5, 0.5);
gamesStatText.x = 1024;
gamesStatText.y = yPosition + spacing * 3;
statisticsMenuContainer.addChild(gamesStatText);
// Achievements
var achievementStatText = new Text2('Başarımlar: ' + achievementsUnlocked + '/4', {
size: 60,
fill: '#00FF00'
});
achievementStatText.anchor.set(0.5, 0.5);
achievementStatText.x = 1024;
achievementStatText.y = yPosition + spacing * 4;
statisticsMenuContainer.addChild(achievementStatText);
// Player Names Section
var playerNamesTitle = new Text2('Oyuncular:', {
size: 70,
fill: '#FFD700'
});
playerNamesTitle.anchor.set(0.5, 0.5);
playerNamesTitle.x = 1024;
playerNamesTitle.y = yPosition + spacing * 5.5;
statisticsMenuContainer.addChild(playerNamesTitle);
// Get all player names from storage (stored as an array)
var playerNames = storage.playerNames || [];
// Create a display text that shows all players publicly to everyone
var displayText = playerNames.length > 0 ? 'Tüm Oyuncular: ' + playerNames.join(', ') : 'Henüz oyuncu yok';
// Allow longer text to show more player names
if (displayText.length > 80) {
displayText = displayText.substring(0, 80) + '...';
}
var playerNamesText = new Text2(displayText, {
size: 45,
fill: '#FFFFFF'
});
playerNamesText.anchor.set(0.5, 0.5);
playerNamesText.x = 1024;
playerNamesText.y = yPosition + spacing * 6.5;
statisticsMenuContainer.addChild(playerNamesText);
// Back button
var backButton = LK.getAsset('progressBarBg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.2
});
backButton.x = 1024;
backButton.y = 1800;
statisticsMenuContainer.addChild(backButton);
var backButtonText = new Text2('GERİ', {
size: 70,
fill: '#FFFFFF'
});
backButtonText.anchor.set(0.5, 0.5);
backButtonText.x = 1024;
backButtonText.y = 1800;
statisticsMenuContainer.addChild(backButtonText);
// Store button reference for click detection
statisticsMenuContainer.backButton = backButton;
}
// Create settings menu
function createSettingsMenu() {
settingsMenuContainer = new Container();
game.addChild(settingsMenuContainer);
settingsMenuContainer.alpha = 0;
// Settings title
var settingsTitle = new Text2('AYARLAR', {
size: 120,
fill: '#FFD700'
});
settingsTitle.anchor.set(0.5, 0.5);
settingsTitle.x = 1024;
settingsTitle.y = 600;
settingsMenuContainer.addChild(settingsTitle);
// Music volume info (since LK handles music automatically)
var musicText = new Text2('Müzik: Otomatik', {
size: 60,
fill: '#FFFFFF'
});
musicText.anchor.set(0.5, 0.5);
musicText.x = 1024;
musicText.y = 1000;
settingsMenuContainer.addChild(musicText);
// Sound effects info
var soundText = new Text2('Ses Efektleri: Açık', {
size: 60,
fill: '#FFFFFF'
});
soundText.anchor.set(0.5, 0.5);
soundText.x = 1024;
soundText.y = 1150;
settingsMenuContainer.addChild(soundText);
// Back button
var backButton = LK.getAsset('progressBarBg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.2
});
backButton.x = 1024;
backButton.y = 1800;
settingsMenuContainer.addChild(backButton);
var backButtonText = new Text2('GERİ', {
size: 70,
fill: '#FFFFFF'
});
backButtonText.anchor.set(0.5, 0.5);
backButtonText.x = 1024;
backButtonText.y = 1800;
settingsMenuContainer.addChild(backButtonText);
// Store button reference for click detection
settingsMenuContainer.backButton = backButton;
}
// Create game container to hold all game elements
function createGameContainer() {
gameContainer = new Container();
game.addChild(gameContainer);
gameContainer.alpha = 0;
}
// Initialize menus
createMainMenu();
createSettingsMenu();
createStatisticsMenu();
createSavesMenu();
createGameContainer();
// Create grid background
var gridBg = game.attachAsset('gridBackground', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1366
});
gameContainer.addChild(gridBg);
// Create grid lines
for (var i = 0; i <= GRID_SIZE; i++) {
// Vertical lines
var verticalLine = LK.getAsset('gridLine', {
width: 4,
height: GRID_SIZE * CELL_SIZE,
color: 0x000000,
shape: 'box',
anchorX: 0.5,
anchorY: 0.5,
x: GRID_START_X + i * CELL_SIZE,
y: GRID_START_Y + GRID_SIZE * CELL_SIZE / 2
});
gameContainer.addChild(verticalLine);
// Horizontal lines
var horizontalLine = LK.getAsset('gridLine', {
width: GRID_SIZE * CELL_SIZE,
height: 4,
color: 0x000000,
shape: 'box',
anchorX: 0.5,
anchorY: 0.5,
x: GRID_START_X + GRID_SIZE * CELL_SIZE / 2,
y: GRID_START_Y + i * CELL_SIZE
});
gameContainer.addChild(horizontalLine);
}
// Create UI elements
var scoreText = new Text2('Score: 0', {
size: 80,
fill: '#FFFFFF'
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
scoreText.y = 100;
var levelText = new Text2('Level: 1', {
size: 60,
fill: '#FFFFFF'
});
levelText.anchor.set(0, 0);
LK.gui.topLeft.addChild(levelText);
levelText.x = 120;
levelText.y = 100;
var goldText = new Text2('Gold: 0', {
size: 60,
fill: '#FFD700'
});
goldText.anchor.set(1, 0);
LK.gui.topRight.addChild(goldText);
goldText.x = -20;
goldText.y = 100;
// Create hourglass display
var hourglassText = new Text2('Hourglass: 0', {
size: 50,
fill: '#FFD700'
});
hourglassText.anchor.set(1, 0);
LK.gui.topRight.addChild(hourglassText);
hourglassText.x = -20;
hourglassText.y = 170;
// Create combo display text
var comboText = new Text2('', {
size: 100,
fill: '#FFFF00'
});
comboText.anchor.set(0.5, 0.5);
LK.gui.center.addChild(comboText);
comboText.alpha = 0; // Start invisible
// Create level progress bar
var progressBarBg = LK.getAsset('progressBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
LK.gui.top.addChild(progressBarBg);
progressBarBg.y = 200;
var progressBarFill = LK.getAsset('progressBarFill', {
anchorX: 0,
anchorY: 0.5
});
progressBarBg.addChild(progressBarFill);
progressBarFill.x = -300; // Start from left edge of background
progressBarFill.scaleX = 0; // Start empty
// Initialize grid
function initializeGrid() {
grid = [];
for (var row = 0; row < GRID_SIZE; row++) {
grid[row] = [];
for (var col = 0; col < GRID_SIZE; col++) {
// Normal candy creation with 5% chance for purple
var color;
if (Math.random() < 0.05) {
// 5% chance for purple fruit
color = 'purple';
} else {
color = COLORS[Math.floor(Math.random() * COLORS.length)];
}
var candy = new Candy(color, row, col);
candy.x = GRID_START_X + col * CELL_SIZE + CELL_SIZE / 2;
candy.y = GRID_START_Y + row * CELL_SIZE + CELL_SIZE / 2;
grid[row][col] = candy;
gameContainer.addChild(candy);
}
}
}
function removeInitialMatches() {
var hasMatches = true;
while (hasMatches) {
hasMatches = false;
for (var row = 0; row < GRID_SIZE; row++) {
for (var col = 0; col < GRID_SIZE; col++) {
if (checkMatch(row, col).length >= 3) {
hasMatches = true;
// Random color with 5% chance for purple
var randomColor;
if (Math.random() < 0.05) {
// 5% chance for purple fruit
randomColor = 'purple';
} else {
randomColor = COLORS[Math.floor(Math.random() * COLORS.length)];
}
grid[row][col].type = randomColor;
grid[row][col].removeChild(grid[row][col].graphics);
var assetMap = {
'blue': 'blueCandy',
'red': 'redCandy',
'green': 'greenCandy',
'orange': 'orangeCandy',
'purple': 'purpleCandy'
};
grid[row][col].graphics = grid[row][col].attachAsset(assetMap[randomColor], {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
});
}
}
}
}
}
function getCandyAt(x, y) {
var col = Math.floor((x - GRID_START_X) / CELL_SIZE);
var row = Math.floor((y - GRID_START_Y) / CELL_SIZE);
if (row >= 0 && row < GRID_SIZE && col >= 0 && col < GRID_SIZE && grid[row] && grid[row][col]) {
return grid[row][col];
}
return null;
}
function swapCandies(candy1, candy2) {
if (!candy1 || !candy2 || candy1 === candy2) return false;
var row1 = candy1.row,
col1 = candy1.col;
var row2 = candy2.row,
col2 = candy2.col;
// Check if adjacent
var dx = Math.abs(col1 - col2);
var dy = Math.abs(row1 - row2);
if (dx + dy !== 1) return false;
// Swap in grid
grid[row1][col1] = candy2;
grid[row2][col2] = candy1;
// Update candy properties
candy1.row = row2;
candy1.col = col2;
candy2.row = row1;
candy2.col = col1;
// Animate swap
tween(candy1, {
x: GRID_START_X + col2 * CELL_SIZE + CELL_SIZE / 2,
y: GRID_START_Y + row2 * CELL_SIZE + CELL_SIZE / 2
}, {
duration: 150,
easing: tween.easeOut
});
tween(candy2, {
x: GRID_START_X + col1 * CELL_SIZE + CELL_SIZE / 2,
y: GRID_START_Y + row1 * CELL_SIZE + CELL_SIZE / 2
}, {
duration: 150,
easing: tween.easeOut
});
return true;
}
function checkMatch(row, col) {
if (!grid[row] || !grid[row][col]) return [];
var candy = grid[row][col];
var matches = [candy];
var type = candy.type;
// Check horizontal
for (var c = col - 1; c >= 0 && grid[row][c] && grid[row][c].type === type; c--) {
matches.unshift(grid[row][c]);
}
for (var c = col + 1; c < GRID_SIZE && grid[row][c] && grid[row][c].type === type; c++) {
matches.push(grid[row][c]);
}
if (matches.length >= 3) return matches;
// Check vertical
matches = [candy];
for (var r = row - 1; r >= 0 && grid[r][col] && grid[r][col].type === type; r--) {
matches.unshift(grid[r][col]);
}
for (var r = row + 1; r < GRID_SIZE && grid[r][col] && grid[r][col].type === type; r++) {
matches.push(grid[r][col]);
}
return matches.length >= 3 ? matches : [];
}
function findAllMatches() {
var allMatches = [];
var processed = [];
for (var row = 0; row < GRID_SIZE; row++) {
processed[row] = [];
for (var col = 0; col < GRID_SIZE; col++) {
processed[row][col] = false;
}
}
for (var row = 0; row < GRID_SIZE; row++) {
for (var col = 0; col < GRID_SIZE; col++) {
if (!processed[row][col]) {
var matches = checkMatch(row, col);
if (matches.length >= 3) {
allMatches.push(matches);
for (var i = 0; i < matches.length; i++) {
processed[matches[i].row][matches[i].col] = true;
}
}
}
}
}
return allMatches;
}
function check4x4Formations() {
var formationsFound = false;
// Check all possible 4x4 positions
for (var row = 0; row <= GRID_SIZE - 4; row++) {
for (var col = 0; col <= GRID_SIZE - 4; col++) {
// Check if all 16 positions in the 4x4 area have candies of same type
var firstCandy = grid[row][col];
if (!firstCandy) continue;
var sameType = true;
var formationCandies = [];
// Check all positions in the 4x4 area
for (var r = row; r < row + 4; r++) {
for (var c = col; c < col + 4; c++) {
var currentCandy = grid[r][c];
if (!currentCandy || currentCandy.type !== firstCandy.type) {
sameType = false;
break;
}
formationCandies.push(currentCandy);
}
if (!sameType) break;
}
if (sameType && formationCandies.length === 16) {
// Found a 4x4 formation - trigger horizontal and vertical clearing
formationsFound = true;
// Get the center position of the 4x4 formation
var centerRow = row + 1;
var centerCol = col + 2;
// Clear entire row of the center
for (var c = 0; c < GRID_SIZE; c++) {
if (grid[centerRow][c] && grid[centerRow][c] !== null) {
explodeCandyWithScore(grid[centerRow][c]);
grid[centerRow][c] = null;
}
}
// Clear entire column of the center
for (var r = 0; r < GRID_SIZE; r++) {
if (grid[r][centerCol] && grid[r][centerCol] !== null) {
explodeCandyWithScore(grid[r][centerCol]);
grid[r][centerCol] = null;
}
}
// Add massive bonus for 4x4 formation
score += 5000;
gold += 2500;
comboMultiplier += 10;
updateUI();
// Create spectacular visual effect
LK.effects.flashScreen(0xFFD700, 1000);
LK.getSound('powerup').play();
// Break out of loops since we found a formation
return formationsFound;
}
}
}
return formationsFound;
}
function checkBlackHoleCombinations() {
var combinationsFound = false;
// Check all grid positions for adjacent black holes
for (var row = 0; row < GRID_SIZE; row++) {
for (var col = 0; col < GRID_SIZE; col++) {
var candy = grid[row][col];
if (candy && candy.isSpecial && candy.specialType === 'blackHole') {
// Check adjacent positions for other black holes
var adjacentPositions = [[-1, 0], [1, 0], [0, -1], [0, 1]];
for (var a = 0; a < adjacentPositions.length; a++) {
var adjRow = row + adjacentPositions[a][0];
var adjCol = col + adjacentPositions[a][1];
if (adjRow >= 0 && adjRow < GRID_SIZE && adjCol >= 0 && adjCol < GRID_SIZE) {
var adjacentCandy = grid[adjRow][adjCol];
if (adjacentCandy && adjacentCandy.isSpecial && adjacentCandy.specialType === 'blackHole') {
// Found two adjacent black holes - combine them into supernova
combinationsFound = true;
// Invalidate special properties of both black holes before combining
candy.isSpecial = false;
candy.specialType = null;
adjacentCandy.isSpecial = false;
adjacentCandy.specialType = null;
// Transform first black hole into supernova
candy.makeSpecial('supernova');
// Remove second black hole
grid[adjRow][adjCol] = null;
adjacentCandy.explode();
// Ensure the supernova stays in the grid and is not processed for removal
candy.justCreated = true;
// Create spectacular combination effect
tween(candy.graphics, {
scaleX: 2.5,
scaleY: 2.5,
tint: 0xFFD700,
rotation: Math.PI * 6
}, {
duration: 1500,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Add continuous pulsing glow effect
var _pulseSuperNova2 = function pulseSuperNova() {
if (candy && candy.isSpecial && candy.specialType === 'supernova' && candy.parent) {
tween(candy.graphics, {
scaleX: 1.5,
scaleY: 1.5,
tint: 0xFFFF00
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(candy.graphics, {
scaleX: 1.3,
scaleY: 1.3,
tint: 0xFFFFFF
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
LK.setTimeout(_pulseSuperNova2, 200);
}
});
}
});
}
};
_pulseSuperNova2();
LK.effects.flashScreen(0xFFD700, 800);
}
});
// Add bonus score for combination
score += 3000;
gold += 1500;
updateUI();
LK.getSound('powerup').play();
// Skip checking other adjacent positions for this candy
break;
}
}
}
}
}
}
return combinationsFound;
}
function processMatches() {
var allMatches = findAllMatches();
if (allMatches.length === 0) {
// Check if this was a cascade (not user-initiated)
var currentTime = Date.now();
if (currentTime - lastCascadeTime < 2000 && cascadeComboCount > 0) {
// This was part of a cascade sequence, don't reset cascade combo yet
// Reset cascade combo after a delay if no more matches found
LK.setTimeout(function () {
// Save current combo count before resetting
if (cascadeComboCount > savedComboCount) {
savedComboCount = cascadeComboCount;
}
// Only reset if not in hourglass super combo mode
if (savedComboCount < 3) {
cascadeComboCount = 0;
} else {
// Keep combo at super combo level when hourglass is active
cascadeComboCount = savedComboCount;
}
}, 1000);
} else {
// Save current combo count before resetting
if (cascadeComboCount > savedComboCount) {
savedComboCount = cascadeComboCount;
}
// Only reset if not in hourglass super combo mode
if (savedComboCount < 3) {
cascadeComboCount = 0; // Reset if too much time passed or no cascade
} else {
// Keep combo at super combo level when hourglass is active
cascadeComboCount = savedComboCount;
}
}
comboMultiplier = 1;
showComboDisplay(); // Hide combo display when combo ends
isProcessing = false;
return;
}
// Check for timeless black hole combinations first
for (var m = 0; m < allMatches.length; m++) {
if (handleTimelessBlackHoleCombo(allMatches[m])) {
// Remove match to prevent further processing
allMatches[m].length = 0;
}
}
// Check for eternal candy combinations
for (var m = 0; m < allMatches.length; m++) {
var matches = allMatches[m];
// Find if any eternal candy is in this match
var eternalCandy = null;
for (var i = 0; i < matches.length; i++) {
if (isEternalCandy(matches[i])) {
eternalCandy = matches[i];
break;
}
}
if (eternalCandy && matches.length >= 3) {
// Eternal candy combo - trigger 6x6 attraction with 80% bonus
LK.setTimeout(function () {
triggerEternal6x6Attraction(eternalCandy);
}, 300);
// Clear match to prevent further processing
matches.length = 0;
}
}
// Check for timeless Karadeniz combinations first
checkTimelessKaradenizCombinations(allMatches);
// Process matches and create special candies
var totalScore = 0;
var totalGold = 0;
for (var m = 0; m < allMatches.length; m++) {
var matches = allMatches[m];
// --- VOID LOGIC: handle 4-void combo first ---
if (handleFourVoidCombo(matches)) {
// Remove all candies from this match to prevent further processing
matches.length = 0;
continue;
}
// --- VOID LOGIC: handle void combo (transform or spread) ---
if (handleVoidCombo(matches)) {
// Remove all candies from this match to prevent further processing
matches.length = 0;
continue;
}
var matchScore = matches.length * 10 * comboMultiplier;
var matchGold = matches.length * 5;
if (comboMultiplier > 1) {
matchGold += 50; // Combo bonus
}
totalScore += matchScore;
totalGold += matchGold;
// Check for special candy creation
if (matches.length >= 7) {
// Create supernova with visual effect but don't activate it
var centerCandy = matches[Math.floor(matches.length / 2)];
centerCandy.makeSpecial('supernova');
// Add creation sparkle effect
tween(centerCandy.graphics, {
scaleX: 1.3,
scaleY: 1.3,
tint: 0xFFFFFF
}, {
duration: 500,
easing: tween.bounceOut,
onFinish: function onFinish() {
// Add continuous pulsing glow effect
var _pulseSuperNova = function pulseSuperNova() {
if (centerCandy && centerCandy.isSpecial && centerCandy.specialType === 'supernova' && centerCandy.parent) {
tween(centerCandy.graphics, {
scaleX: 1.5,
scaleY: 1.5,
tint: 0xFFFF00
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(centerCandy.graphics, {
scaleX: 1.3,
scaleY: 1.3,
tint: 0xFFFFFF
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
LK.setTimeout(_pulseSuperNova, 200);
}
});
}
});
}
};
_pulseSuperNova();
}
});
// Don't remove the supernova from matches - keep it on the board
// Skip removing the supernova so it stays on the grid
var centerIndex = Math.floor(matches.length / 2);
matches.splice(centerIndex, 1);
} else if (matches.length >= 6) {
// Create disco ball with visual effect
var centerCandy = matches[Math.floor(matches.length / 2)];
centerCandy.makeSpecial('discoBall');
// Add creation sparkle effect
tween(centerCandy.graphics, {
scaleX: 1.0,
scaleY: 1.0,
rotation: Math.PI
}, {
duration: 300,
easing: tween.bounceOut
});
// Add continuous rotation to disco ball with optimized performance
var _rotateDiscoBall = function rotateDiscoBall() {
if (centerCandy.isSpecial && centerCandy.specialType === 'discoBall' && centerCandy.parent) {
tween(centerCandy.graphics, {
rotation: centerCandy.graphics.rotation + Math.PI * 2
}, {
duration: 6000,
// Slower rotation for better performance
easing: tween.linear,
onFinish: function onFinish() {
// Add delay before next rotation to reduce CPU load
LK.setTimeout(_rotateDiscoBall, 100);
}
});
}
};
_rotateDiscoBall();
matches.splice(Math.floor(matches.length / 2), 1);
} else if (matches.length === 5) {
// Create special based on color with unique effects
var centerCandy = matches[2];
var color = centerCandy.type;
var specialType;
if (color === 'blue') {
// Create converter instead of blueBomb for blue 5-match
centerCandy.makeSpecial('vriper'); // Use vriper as converter visual
centerCandy.specialType = 'converter'; // Set special type to converter
// Add converter creation effect
tween(centerCandy.graphics, {
scaleX: 1.2,
scaleY: 1.2,
tint: 0x4a90e2
}, {
duration: 500,
easing: tween.bounceOut,
onFinish: function onFinish() {
// Add pulsing blue glow effect for converter
var _pulseConverter = function pulseConverter() {
if (centerCandy.isSpecial && centerCandy.specialType === 'converter' && centerCandy.parent) {
tween(centerCandy.graphics, {
scaleX: 1.4,
scaleY: 1.4,
tint: 0x6ba3f0
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(centerCandy.graphics, {
scaleX: 1.2,
scaleY: 1.2,
tint: 0x4a90e2
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
LK.setTimeout(_pulseConverter, 100);
}
});
}
});
}
};
_pulseConverter();
}
});
} else if (color === 'red') {
specialType = 'redRocket';
} else if (color === 'green') {
specialType = 'greenPentagon';
} else if (color === 'orange') {
specialType = 'orangeLollipop';
} else if (color === 'purple') {
// Check if this is purple candy - create black hole instead
centerCandy.makeSpecial('blackHole');
// Add black hole creation effect
tween(centerCandy.graphics, {
scaleX: 1.2,
scaleY: 1.2,
alpha: 0.8
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Add pulsing animation to black hole
var _pulseBlackHole2 = function _pulseBlackHole() {
if (centerCandy.isSpecial && centerCandy.specialType === 'blackHole' && centerCandy.parent) {
tween(centerCandy.graphics, {
scaleX: 1.4,
scaleY: 1.4,
alpha: 0.6
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(centerCandy.graphics, {
scaleX: 1.2,
scaleY: 1.2,
alpha: 0.8
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
LK.setTimeout(_pulseBlackHole2, 100);
}
});
}
});
}
};
_pulseBlackHole2();
}
});
} else {
specialType = 'purpleBerry';
}
if (color !== 'purple' && color !== 'blue') {
centerCandy.makeSpecial(specialType);
}
matches.splice(2, 1);
}
// Explode remaining matches with staggered timing to reduce simultaneous animations
for (var i = 0; i < matches.length; i++) {
var candy = matches[i];
var candyRow = candy.row;
var candyCol = candy.col;
grid[candy.row][candy.col] = null;
// Stagger explosions to reduce simultaneous tween load
(function (candyToExplode, delay) {
LK.setTimeout(function () {
candyToExplode.explode();
}, delay);
})(candy, i * 100);
}
}
score += totalScore;
gold += totalGold;
comboMultiplier += 5;
showComboDisplay(); // Show updated combo display
var newLevel = 1;
// Calculate required score for next level (50000 for level 2, then quadruple each time)
function getRequiredScoreForLevel(targetLevel) {
if (targetLevel <= 1) return 0;
if (targetLevel === 2) return 50000;
// For levels 3+: 50000 * 4^(level-2)
return 50000 * Math.pow(4, targetLevel - 2);
}
// Update level based on new progression system
while (score >= getRequiredScoreForLevel(newLevel + 1)) {
newLevel++;
}
if (newLevel > level) {
level = newLevel;
// Check for level 7 victory
if (level >= 7) {
// Start level 7 victory sequence
startLevel7Victory();
return;
}
// Level up animation - flash progress bar
tween(progressBarFill, {
tint: 0xFFFF00
}, {
duration: 200,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(progressBarFill, {
tint: 0x00FF00
}, {
duration: 200,
easing: tween.easeInOut
});
}
});
// Show level up notification
showLevelUpNotification(level);
// Add +1000 gold for each level completed
gold += 1000;
if (level % 5 === 0) {
gold += 4000;
}
// Check for Leagues achievement
checkLeaguesAchievement();
}
updateUI();
LK.getSound('match').play();
// Check for 4x4 formations before black hole combinations
check4x4Formations();
// Check for black hole combinations before dropping candies
checkBlackHoleCombinations();
// Track cascade combo if this was an auto-cascade (not user-initiated)
var currentTime = Date.now();
if (currentTime - lastCascadeTime < 2000 || lastCascadeTime === 0) {
// If hourglass is active and we're at super combo level, add to it instead of incrementing normally
if (savedComboCount >= 3 && cascadeComboCount >= 3) {
// Player is in hourglass super combo mode - add to the super combo
cascadeComboCount++;
} else {
cascadeComboCount++;
}
lastCascadeTime = currentTime;
// Show cascade combo display for levels 1-7
if (cascadeComboCount >= 1 && cascadeComboCount <= 7) {
showCascadeComboDisplay(cascadeComboCount);
}
// Special reward: Create supernova if reached 7th cascade combo
if (cascadeComboCount === 7) {
createSupernovaReward();
}
}
// Drop candies and continue processing
LK.setTimeout(function () {
dropCandies();
LK.setTimeout(function () {
processMatches();
}, 300);
}, 400);
}
function dropCandies() {
// Always ensure no empty squares remain by filling all null positions
for (var col = 0; col < GRID_SIZE; col++) {
var writeRow = GRID_SIZE - 1;
// Move existing candies down
for (var row = GRID_SIZE - 1; row >= 0; row--) {
if (grid[row] && grid[row][col] !== null && grid[row][col] !== undefined) {
// Move candy down to available position
if (row !== writeRow) {
var candyToMove = grid[row][col];
grid[writeRow][col] = candyToMove;
grid[row][col] = null;
if (candyToMove) {
candyToMove.row = writeRow;
candyToMove.col = col;
tween(candyToMove, {
y: GRID_START_Y + writeRow * CELL_SIZE + CELL_SIZE / 2
}, {
duration: 150,
easing: tween.easeOut
});
}
}
writeRow--;
}
}
// Create new candies for ALL empty spaces - ensuring no empty squares remain
for (var row = writeRow; row >= 0; row--) {
var candy;
if (onlySpecialCandies) {
// Create only special candies (disco ball, rocket, bomb, black hole, supernova)
var specialTypes = ['discoBall', 'redRocket', 'blueBomb', 'blackHole', 'supernova', 'expires', 'writerpir', 'vriper', 'converter'];
var randomSpecialType = specialTypes[Math.floor(Math.random() * specialTypes.length)];
var randomColor = COLORS[Math.floor(Math.random() * COLORS.length)];
candy = new Candy(randomColor, row, col);
candy.x = GRID_START_X + col * CELL_SIZE + CELL_SIZE / 2;
// Start candies above the visible grid area
var emptySpaces = writeRow + 1;
var startRow = row - emptySpaces;
candy.y = GRID_START_Y + startRow * CELL_SIZE + CELL_SIZE / 2;
// Make it special immediately
candy.makeSpecial(randomSpecialType);
// Check for Universe achievement if expires (Karadeniz) was created
if (randomSpecialType === 'expires') {
checkUniverseAchievement();
}
} else {
// Normal candy creation with 5% chance for purple
var randomColor;
if (Math.random() < 0.05) {
// 5% chance for purple fruit
randomColor = 'purple';
} else {
randomColor = COLORS[Math.floor(Math.random() * COLORS.length)];
}
candy = new Candy(randomColor, row, col);
candy.x = GRID_START_X + col * CELL_SIZE + CELL_SIZE / 2;
// Start candies above the visible grid area
var emptySpaces = writeRow + 1;
var startRow = row - emptySpaces;
candy.y = GRID_START_Y + startRow * CELL_SIZE + CELL_SIZE / 2;
}
grid[row][col] = candy;
gameContainer.addChild(candy);
// Animate falling with bounce effect
tween(candy, {
y: GRID_START_Y + row * CELL_SIZE + CELL_SIZE / 2
}, {
duration: 200 + (emptySpaces - (writeRow - row)) * 30,
easing: tween.bounceOut
});
}
}
// Double-check: Fill any remaining null positions (safety measure)
for (var row = 0; row < GRID_SIZE; row++) {
for (var col = 0; col < GRID_SIZE; col++) {
if (grid[row][col] === null) {
var candy;
if (onlySpecialCandies) {
var specialTypes = ['discoBall', 'redRocket', 'blueBomb', 'blackHole', 'supernova', 'expires', 'writerpir', 'vriper', 'converter'];
var randomSpecialType = specialTypes[Math.floor(Math.random() * specialTypes.length)];
var randomColor = COLORS[Math.floor(Math.random() * COLORS.length)];
candy = new Candy(randomColor, row, col);
candy.x = GRID_START_X + col * CELL_SIZE + CELL_SIZE / 2;
candy.y = GRID_START_Y - CELL_SIZE; // Start slightly above
candy.makeSpecial(randomSpecialType);
// Check for Universe achievement if expires (Karadeniz) was created
if (randomSpecialType === 'expires') {
checkUniverseAchievement();
}
} else {
// Normal candy creation with 5% chance for purple
var randomColor;
if (Math.random() < 0.05) {
// 5% chance for purple fruit
randomColor = 'purple';
} else {
randomColor = COLORS[Math.floor(Math.random() * COLORS.length)];
}
candy = new Candy(randomColor, row, col);
candy.x = GRID_START_X + col * CELL_SIZE + CELL_SIZE / 2;
candy.y = GRID_START_Y - CELL_SIZE; // Start slightly above
}
grid[row][col] = candy;
gameContainer.addChild(candy);
// Animate to final position
tween(candy, {
y: GRID_START_Y + row * CELL_SIZE + CELL_SIZE / 2
}, {
duration: 250,
easing: tween.bounceOut
});
}
}
}
// Add special bonus if entire grid was cleared
var totalCandies = 0;
for (var checkRow = 0; checkRow < GRID_SIZE; checkRow++) {
for (var checkCol = 0; checkCol < GRID_SIZE; checkCol++) {
if (grid[checkRow][checkCol] !== null) {
totalCandies++;
}
}
}
if (totalCandies === GRID_SIZE * GRID_SIZE) {
// Grid was completely refilled - give bonus
score += 5000;
gold += 2500;
updateUI();
LK.effects.flashScreen(0xFFD700, 500); // Gold flash for complete refill
}
}
function explodeCandyWithScore(candy) {
if (!candy || !candy.parent) return;
// Add score and gold for each exploding candy
var candyScore = 15 * comboMultiplier;
var candyGold = 8;
if (comboMultiplier > 1) {
candyGold += 10; // Combo bonus
}
score += candyScore;
gold += candyGold;
// Stop any existing tweens on this candy to prevent conflicts
tween.stop(candy);
if (candy.graphics) {
tween.stop(candy.graphics);
}
// Explode the candy
candy.explode();
}
function showComboDisplay() {
if (comboMultiplier > 1) {
// Update combo text
comboText.setText('COMBO x' + comboMultiplier);
// Show combo text with scale animation
comboText.alpha = 1;
comboText.scaleX = 0.5;
comboText.scaleY = 0.5;
tween(comboText, {
scaleX: 1.2,
scaleY: 1.2,
alpha: 1
}, {
duration: 200,
easing: tween.easeInOut
});
} else {
// Hide combo text when combo ends
tween(comboText, {
alpha: 0,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 200,
easing: tween.easeOut
});
}
}
function updateUI() {
// Load gold from storage to ensure synchronization
gold = storage.gold || 0;
scoreText.setText('Score: ' + score);
levelText.setText('Level: ' + level);
goldText.setText('Gold: ' + gold);
hourglassText.setText('Hourglass: ' + hourglassCount);
// Save gold to storage
storage.gold = gold;
// Update statistics
if (!storage.highestScore || score > storage.highestScore) {
storage.highestScore = score;
}
if (!storage.highestLevel || level > storage.highestLevel) {
storage.highestLevel = level;
}
if (!storage.totalGoldEarned) {
storage.totalGoldEarned = 0;
}
storage.totalGoldEarned += gold - (storage.lastGold || 0);
storage.lastGold = gold;
// Update progress bar using new level progression system
var currentLevelScore = getRequiredScoreForLevel(level);
var nextLevelScore = getRequiredScoreForLevel(level + 1);
var progress = (score - currentLevelScore) / (nextLevelScore - currentLevelScore);
progress = Math.max(0, Math.min(1, progress)); // Clamp between 0 and 1
// Animate progress bar fill
tween(progressBarFill, {
scaleX: progress
}, {
duration: 200,
easing: tween.easeInOut
});
}
function activateSpecialCandy(candy) {
if (!candy.isSpecial) return;
var row = candy.row;
var col = candy.col;
switch (candy.specialType) {
case 'blueBomb':
// Destroy 3x3 area
for (var r = Math.max(0, row - 1); r <= Math.min(GRID_SIZE - 1, row + 1); r++) {
for (var c = Math.max(0, col - 1); c <= Math.min(GRID_SIZE - 1, col + 1); c++) {
if (grid[r][c] && grid[r][c] !== candy) {
explodeCandyWithScore(grid[r][c]);
grid[r][c] = null;
}
}
}
break;
case 'redRocket':
// Clear entire row and column
for (var c = 0; c < GRID_SIZE; c++) {
if (grid[row][c] && grid[row][c] !== candy) {
explodeCandyWithScore(grid[row][c]);
grid[row][c] = null;
}
}
for (var r = 0; r < GRID_SIZE; r++) {
if (grid[r][col] && grid[r][col] !== candy) {
explodeCandyWithScore(grid[r][col]);
grid[r][col] = null;
}
}
break;
case 'greenPentagon':
// Destroy candies in a plus pattern (5 directions)
var directions = [[-2, 0], [-1, 0], [0, 0], [1, 0], [2, 0],
// Horizontal line
[0, -2], [0, -1], [0, 1], [0, 2] // Vertical line (excluding center)
];
for (var d = 0; d < directions.length; d++) {
var newRow = row + directions[d][0];
var newCol = col + directions[d][1];
if (newRow >= 0 && newRow < GRID_SIZE && newCol >= 0 && newCol < GRID_SIZE) {
if (grid[newRow][newCol] && grid[newRow][newCol] !== candy) {
explodeCandyWithScore(grid[newRow][newCol]);
grid[newRow][newCol] = null;
}
}
}
break;
case 'orangeLollipop':
// Destroy all candies of the same color as adjacent candies
var adjacentColors = [];
var adjacentPositions = [[-1, 0], [1, 0], [0, -1], [0, 1]];
for (var a = 0; a < adjacentPositions.length; a++) {
var adjRow = row + adjacentPositions[a][0];
var adjCol = col + adjacentPositions[a][1];
if (adjRow >= 0 && adjRow < GRID_SIZE && adjCol >= 0 && adjCol < GRID_SIZE) {
if (grid[adjRow][adjCol] && adjacentColors.indexOf(grid[adjRow][adjCol].type) === -1) {
adjacentColors.push(grid[adjRow][adjCol].type);
}
}
}
// Destroy all candies of adjacent colors with staggered timing
var destroyIndex = 0;
for (var r = 0; r < GRID_SIZE; r++) {
for (var c = 0; c < GRID_SIZE; c++) {
if (grid[r][c] && grid[r][c] !== candy && adjacentColors.indexOf(grid[r][c].type) !== -1) {
(function (targetCandy, delay) {
LK.setTimeout(function () {
if (targetCandy.parent) {
tween(targetCandy.graphics, {
tint: 0xFFA500
}, {
duration: 100,
onFinish: function onFinish() {
explodeCandyWithScore(targetCandy);
grid[targetCandy.row][targetCandy.col] = null;
}
});
}
}, delay);
})(grid[r][c], destroyIndex * 30);
destroyIndex++;
}
}
}
break;
case 'purpleBerry':
// Create a wave effect that spreads outward in rings
var maxDistance = 3;
for (var distance = 1; distance <= maxDistance; distance++) {
(function (dist) {
LK.setTimeout(function () {
for (var r = Math.max(0, row - dist); r <= Math.min(GRID_SIZE - 1, row + dist); r++) {
for (var c = Math.max(0, col - dist); c <= Math.min(GRID_SIZE - 1, col + dist); c++) {
// Only destroy candies on the ring edge
var actualDist = Math.max(Math.abs(r - row), Math.abs(c - col));
if (actualDist === dist && grid[r][c] && grid[r][c] !== candy) {
tween(grid[r][c].graphics, {
tint: 0x9013fe,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 150,
onFinish: function onFinish() {
if (grid[r] && grid[r][c]) {
explodeCandyWithScore(grid[r][c]);
grid[r][c] = null;
}
}
});
}
}
}
}, (dist - 1) * 200);
})(distance);
}
break;
case 'discoBall':
// Check if we're combining with purple candy first
var adjacentPurpleCandies = [];
var adjacentPositions = [[-1, 0], [1, 0], [0, -1], [0, 1]];
for (var a = 0; a < adjacentPositions.length; a++) {
var adjRow = row + adjacentPositions[a][0];
var adjCol = col + adjacentPositions[a][1];
if (adjRow >= 0 && adjRow < GRID_SIZE && adjCol >= 0 && adjCol < GRID_SIZE) {
if (grid[adjRow][adjCol] && grid[adjRow][adjCol].type === 'purple' && !grid[adjRow][adjCol].isSpecial) {
adjacentPurpleCandies.push(grid[adjRow][adjCol]);
}
}
}
// Check if we're combining with red rocket first
var adjacentRedRockets = [];
for (var a = 0; a < adjacentPositions.length; a++) {
var adjRow = row + adjacentPositions[a][0];
var adjCol = col + adjacentPositions[a][1];
if (adjRow >= 0 && adjRow < GRID_SIZE && adjCol >= 0 && adjCol < GRID_SIZE) {
if (grid[adjRow][adjCol] && grid[adjRow][adjCol].isSpecial && grid[adjRow][adjCol].specialType === 'redRocket') {
adjacentRedRockets.push(grid[adjRow][adjCol]);
}
}
}
if (adjacentRedRockets.length > 0) {
// Disco ball + red rocket combo: transform all candies to random candy types (no explosions)
var redRocketCandy = adjacentRedRockets[0];
// Remove red rocket without explosion
grid[redRocketCandy.row][redRocketCandy.col] = null;
if (redRocketCandy.parent) {
redRocketCandy.parent.removeChild(redRocketCandy);
}
// Create spectacular combination effect
tween(candy.graphics, {
scaleX: 2.0,
scaleY: 2.0,
tint: 0xFF0000,
rotation: Math.PI * 4
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Transform all candies to random candy types
for (var r = 0; r < GRID_SIZE; r++) {
for (var c = 0; c < GRID_SIZE; c++) {
if (grid[r][c] && grid[r][c] !== candy) {
var targetCandy = grid[r][c];
// Choose random candy type
var randomColor = COLORS[Math.floor(Math.random() * COLORS.length)];
// Transform candy with delay for visual effect
(function (candyToTransform, newColor, delay) {
LK.setTimeout(function () {
if (candyToTransform && candyToTransform.parent) {
// Update candy type
candyToTransform.type = newColor;
// Remove old graphics
candyToTransform.removeChild(candyToTransform.graphics);
// Create new graphics with new color
var assetMap = {
'blue': 'blueCandy',
'red': 'redCandy',
'green': 'greenCandy',
'orange': 'orangeCandy',
'purple': 'purpleCandy'
};
candyToTransform.graphics = candyToTransform.attachAsset(assetMap[newColor], {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
});
// Reset special properties if any
candyToTransform.isSpecial = false;
candyToTransform.specialType = null;
// Add transformation effect
tween(candyToTransform.graphics, {
scaleX: 1.2,
scaleY: 1.2,
tint: 0xFFFFFF
}, {
duration: 300,
easing: tween.bounceOut,
onFinish: function onFinish() {
tween(candyToTransform.graphics, {
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 200,
easing: tween.easeOut
});
}
});
}
}, delay);
})(targetCandy, randomColor, (r + c) * 30);
}
}
}
LK.effects.flashScreen(0xFF0000, 800);
}
});
// Add bonus score for combination
score += 5000;
gold += 2500;
updateUI();
LK.getSound('powerup').play();
break;
}
if (adjacentPurpleCandies.length > 0) {
// Disco ball + purple combo: create white shining vriper
var purpleCandy = adjacentPurpleCandies[0];
// Transform this disco ball into vriper
candy.makeSpecial('vriper');
// Remove purple candy
grid[purpleCandy.row][purpleCandy.col] = null;
purpleCandy.explode();
// Create spectacular combination effect
tween(candy.graphics, {
scaleX: 2.0,
scaleY: 2.0,
tint: 0xFFFFFF,
rotation: Math.PI * 4
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Add continuous white shining effect
var _shineVriper = function shineVriper() {
if (candy && candy.isSpecial && candy.specialType === 'vriper' && candy.parent) {
tween(candy.graphics, {
scaleX: 1.3,
scaleY: 1.3,
tint: 0xFFFFFF,
alpha: 1.0
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(candy.graphics, {
scaleX: 1.1,
scaleY: 1.1,
tint: 0xF0F0F0,
alpha: 0.9
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
LK.setTimeout(_shineVriper, 100);
}
});
}
});
}
};
_shineVriper();
LK.effects.flashScreen(0xFFFFFF, 800);
}
});
// Add bonus score for combination
score += 4000;
gold += 2000;
updateUI();
LK.getSound('powerup').play();
break;
}
// Check if we're combining with another disco ball
var adjacentDiscoBalls = [];
for (var a = 0; a < adjacentPositions.length; a++) {
var adjRow = row + adjacentPositions[a][0];
var adjCol = col + adjacentPositions[a][1];
if (adjRow >= 0 && adjRow < GRID_SIZE && adjCol >= 0 && adjCol < GRID_SIZE) {
if (grid[adjRow][adjCol] && grid[adjRow][adjCol].isSpecial && grid[adjRow][adjCol].specialType === 'discoBall') {
adjacentDiscoBalls.push(grid[adjRow][adjCol]);
}
}
}
if (adjacentDiscoBalls.length > 0) {
// Disco ball + disco ball combo: destroy ALL candies on the grid
// Create massive visual effect
tween(candy.graphics, {
scaleX: 2.0,
scaleY: 2.0,
rotation: Math.PI * 4
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Destroy all candies in waves from center outward
var allCandies = [];
for (var r = 0; r < GRID_SIZE; r++) {
for (var c = 0; c < GRID_SIZE; c++) {
if (grid[r][c] && grid[r][c] !== candy) {
// Calculate distance from center for wave effect
var distance = Math.abs(r - row) + Math.abs(c - col);
allCandies.push({
candy: grid[r][c],
distance: distance
});
}
}
}
// Sort by distance for wave effect
allCandies.sort(function (a, b) {
return a.distance - b.distance;
});
// Clear grid immediately to prevent null reference errors
for (var r = 0; r < GRID_SIZE; r++) {
for (var c = 0; c < GRID_SIZE; c++) {
if (grid[r][c] && grid[r][c] !== candy) {
grid[r][c] = null;
}
}
}
// Destroy all candies with wave timing
for (var i = 0; i < allCandies.length; i++) {
(function (candyData, index) {
LK.setTimeout(function () {
var targetCandy = candyData.candy;
if (targetCandy && targetCandy.parent) {
// Flash the candy bright white before exploding
tween(targetCandy.graphics, {
tint: 0xFFFFFF,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 150,
onFinish: function onFinish() {
explodeCandyWithScore(targetCandy);
}
});
}
}, candyData.distance * 80 + index * 20);
})(allCandies[i], i);
}
// Add screen flash effect when all candies are destroyed
LK.setTimeout(function () {
LK.effects.flashScreen(0xFFFFFF, 500);
// After the flash effect, drop new candies to fill the entire grid
LK.setTimeout(function () {
dropCandies();
LK.setTimeout(function () {
processMatches();
}, 300);
}, 500);
}, allCandies.length * 100 + 500);
}
});
} else {
// Normal disco ball activation
// Create sparkle effect on disco ball before activation
tween(candy.graphics, {
scaleX: 1.2,
scaleY: 1.2,
rotation: Math.PI * 2
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Destroy 13 random candies
var randomCandies = [];
for (var r = 0; r < GRID_SIZE; r++) {
for (var c = 0; c < GRID_SIZE; c++) {
if (grid[r][c] && grid[r][c] !== candy) {
randomCandies.push(grid[r][c]);
}
}
}
// Destroy candies with staggered timing for visual effect
var destroyCount = Math.min(13, randomCandies.length);
for (var i = 0; i < destroyCount; i++) {
(function (index) {
LK.setTimeout(function () {
if (randomCandies.length > 0) {
var randomIndex = Math.floor(Math.random() * randomCandies.length);
var randomCandy = randomCandies[randomIndex];
// Flash the candy white before exploding
tween(randomCandy.graphics, {
tint: 0xFFFFFF
}, {
duration: 100,
onFinish: function onFinish() {
explodeCandyWithScore(randomCandy);
grid[randomCandy.row][randomCandy.col] = null;
}
});
randomCandies.splice(randomIndex, 1);
}
}, index * 50);
})(i);
}
}
});
}
break;
case 'supernova':
// Check if we're combining with disco ball
var adjacentDiscoBalls = [];
var adjacentPositions = [[-1, 0], [1, 0], [0, -1], [0, 1]];
for (var a = 0; a < adjacentPositions.length; a++) {
var adjRow = row + adjacentPositions[a][0];
var adjCol = col + adjacentPositions[a][1];
if (adjRow >= 0 && adjRow < GRID_SIZE && adjCol >= 0 && adjCol < GRID_SIZE) {
if (grid[adjRow][adjCol] && grid[adjRow][adjCol].isSpecial && grid[adjRow][adjCol].specialType === 'discoBall') {
adjacentDiscoBalls.push(grid[adjRow][adjCol]);
}
}
}
if (adjacentDiscoBalls.length > 0) {
// Supernova + Disco Ball combo: create writerpir (they disappear and writerpir appears)
var discoBallCandy = adjacentDiscoBalls[0];
// Transform this supernova into writerpir
candy.makeSpecial('writerpir');
// Remove disco ball
grid[discoBallCandy.row][discoBallCandy.col] = null;
discoBallCandy.explode();
// Create spectacular combination effect
tween(candy.graphics, {
scaleX: 2.5,
scaleY: 2.5,
tint: 0x8B0000,
rotation: Math.PI * 6
}, {
duration: 1500,
easing: tween.easeInOut,
onFinish: function onFinish() {
LK.effects.flashScreen(0x8B0000, 800);
}
});
break;
}
// Normal supernova: massive explosion that destroys everything on the grid in expanding waves
// Create expanding wave effect that destroys the entire grid
var maxWaves = Math.max(GRID_SIZE, GRID_SIZE);
for (var wave = 1; wave <= maxWaves; wave++) {
(function (waveDistance) {
LK.setTimeout(function () {
var candiesInWave = [];
// Collect all candies at this wave distance
for (var r = 0; r < GRID_SIZE; r++) {
for (var c = 0; c < GRID_SIZE; c++) {
var distance = Math.max(Math.abs(r - row), Math.abs(c - col));
if (distance === waveDistance && grid[r][c] && grid[r][c] !== candy) {
candiesInWave.push(grid[r][c]);
grid[r][c] = null; // Remove from grid immediately
}
}
}
// Destroy all candies in this wave with spectacular effect
for (var i = 0; i < candiesInWave.length; i++) {
(function (targetCandy, index) {
if (targetCandy && targetCandy.parent) {
// If the target candy is special, activate it first
if (targetCandy.isSpecial) {
// Create a temporary position for the special candy
var tempRow = targetCandy.row;
var tempCol = targetCandy.col;
// Activate the special candy effect
activateSpecialCandy(targetCandy);
} else {
// Flash bright gold then explode
tween(targetCandy.graphics, {
tint: 0xFFD700,
scaleX: 1.8,
scaleY: 1.8,
alpha: 1.0
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
explodeCandyWithScore(targetCandy);
}
});
}
}
})(candiesInWave[i], i);
}
}, waveDistance * 150); // Stagger waves
})(wave);
}
// Create supernova visual effect
tween(candy.graphics, {
scaleX: 3.0,
scaleY: 3.0,
tint: 0xFFFFFF,
alpha: 0.8,
rotation: Math.PI * 6
}, {
duration: 2000,
easing: tween.easeOut,
onFinish: function onFinish() {
// Massive screen flash when supernova completes
LK.effects.flashScreen(0xFFD700, 1000);
// Give massive bonus for supernova activation
score += 10000;
gold += 5000;
updateUI();
}
});
break;
case 'expires':
// Check if we're combining with purple candy first
var adjacentPurpleCandies = [];
var adjacentPositions = [[-1, 0], [1, 0], [0, -1], [0, 1]];
for (var a = 0; a < adjacentPositions.length; a++) {
var adjRow = row + adjacentPositions[a][0];
var adjCol = col + adjacentPositions[a][1];
if (adjRow >= 0 && adjRow < GRID_SIZE && adjCol >= 0 && adjCol < GRID_SIZE) {
if (grid[adjRow][adjCol] && grid[adjRow][adjCol].type === 'purple' && !grid[adjRow][adjCol].isSpecial) {
adjacentPurpleCandies.push(grid[adjRow][adjCol]);
}
}
}
if (adjacentPurpleCandies.length > 0) {
// Expires + Purple candy combo: create void
var purpleCandy = adjacentPurpleCandies[0];
// Remove purple candy
grid[purpleCandy.row][purpleCandy.col] = null;
purpleCandy.explode();
// Transform expires into void
createVoidAt(candy.row, candy.col);
// Create spectacular combination effect
LK.effects.flashScreen(0x6e00ff, 800);
// Show void creation notification
var voidText = new Text2('ZAMANSIZ KARA DELIK + MOR = VOID!', {
size: 80,
fill: '#6e00ff'
});
voidText.anchor.set(0.5, 0.5);
voidText.x = 1024;
voidText.y = 1366;
voidText.alpha = 0;
game.addChild(voidText);
tween(voidText, {
alpha: 1,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 400,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(voidText, {
alpha: 0
}, {
duration: 400,
onFinish: function onFinish() {
if (voidText.parent) voidText.parent.removeChild(voidText);
}
});
}, 1200);
}
});
// Add bonus score for combination
score += 6000;
gold += 3000;
updateUI();
LK.getSound('powerup').play();
break;
}
// Check if we're combining with black hole
var adjacentBlackHoles = [];
for (var a = 0; a < adjacentPositions.length; a++) {
var adjRow = row + adjacentPositions[a][0];
var adjCol = col + adjacentPositions[a][1];
if (adjRow >= 0 && adjRow < GRID_SIZE && adjCol >= 0 && adjCol < GRID_SIZE) {
if (grid[adjRow][adjCol] && grid[adjRow][adjCol].isSpecial && grid[adjRow][adjCol].specialType === 'blackHole') {
adjacentBlackHoles.push(grid[adjRow][adjCol]);
}
}
}
if (adjacentBlackHoles.length > 0) {
// Expires + Black Hole combo: create writerpir
var blackHoleCandy = adjacentBlackHoles[0];
// Transform this expires into writerpir
candy.makeSpecial('writerpir');
// Remove black hole
grid[blackHoleCandy.row][blackHoleCandy.col] = null;
blackHoleCandy.explode();
// Create spectacular combination effect
tween(candy.graphics, {
scaleX: 2.5,
scaleY: 2.5,
tint: 0x8B0000,
rotation: Math.PI * 6
}, {
duration: 1500,
easing: tween.easeInOut,
onFinish: function onFinish() {
LK.effects.flashScreen(0x8B0000, 800);
}
});
break;
}
// Normal expires: turn all candies into a single random non-special, non-redRocket candy type
// Pick a random color from COLORS, but not 'red' (to avoid redRocket), and not a special
var availableColors = [];
for (var i = 0; i < COLORS.length; i++) {
if (COLORS[i] !== 'red') availableColors.push(COLORS[i]);
}
var randomType = availableColors[Math.floor(Math.random() * availableColors.length)];
var assetMap = {
'blue': 'blueCandy',
'green': 'greenCandy',
'orange': 'orangeCandy',
'purple': 'purpleCandy'
};
for (var r = 0; r < GRID_SIZE; r++) {
for (var c = 0; c < GRID_SIZE; c++) {
if (grid[r][c] && grid[r][c] !== candy) {
var targetCandy = grid[r][c];
// Transform to the chosen randomType with delay
(function (candyToTransform, delay) {
LK.setTimeout(function () {
if (candyToTransform && candyToTransform.parent) {
// Remove old graphics
candyToTransform.removeChild(candyToTransform.graphics);
// Set new type
candyToTransform.type = randomType;
// Attach new graphics
candyToTransform.graphics = candyToTransform.attachAsset(assetMap[randomType], {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
});
// Reset special properties
candyToTransform.isSpecial = false;
candyToTransform.specialType = null;
candyToTransform.isTimeless = false;
// Add transformation effect
tween(candyToTransform.graphics, {
scaleX: 1.2,
scaleY: 1.2,
tint: 0xFFFFFF
}, {
duration: 300,
easing: tween.bounceOut,
onFinish: function onFinish() {
tween(candyToTransform.graphics, {
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 200,
easing: tween.easeOut
});
}
});
}
}, delay);
})(targetCandy, (r + c) * 50);
}
}
}
// Create expires visual effect
tween(candy.graphics, {
scaleX: 2.5,
scaleY: 2.5,
tint: 0xFF4500,
rotation: Math.PI * 4
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
LK.effects.flashScreen(0xFF4500, 500);
score += 8000;
gold += 4000;
updateUI();
}
});
break;
case 'writerpir':
// Writerpir: turn entire map into supernovas when it explodes
for (var r = 0; r < GRID_SIZE; r++) {
for (var c = 0; c < GRID_SIZE; c++) {
if (grid[r][c] && grid[r][c] !== candy) {
var targetCandy = grid[r][c];
// Transform to supernova with spectacular delay
(function (candyToTransform, delay) {
LK.setTimeout(function () {
if (candyToTransform && candyToTransform.parent) {
candyToTransform.makeSpecial('supernova');
// Add supernova creation effect
tween(candyToTransform.graphics, {
scaleX: 1.3,
scaleY: 1.3,
tint: 0xFFD700
}, {
duration: 500,
easing: tween.bounceOut,
onFinish: function onFinish() {
// Add continuous pulsing glow effect
var _pulseSuperNova = function pulseSuperNova() {
if (candyToTransform && candyToTransform.isSpecial && candyToTransform.specialType === 'supernova' && candyToTransform.parent) {
tween(candyToTransform.graphics, {
scaleX: 1.5,
scaleY: 1.5,
tint: 0xFFFF00
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(candyToTransform.graphics, {
scaleX: 1.3,
scaleY: 1.3,
tint: 0xFFD700
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
LK.setTimeout(_pulseSuperNova, 200);
}
});
}
});
}
};
_pulseSuperNova();
}
});
}
}, delay);
})(targetCandy, (r + c) * 80);
}
}
}
// Create writerpir visual effect
tween(candy.graphics, {
scaleX: 3.5,
scaleY: 3.5,
tint: 0x8B0000,
rotation: Math.PI * 8,
alpha: 0.9
}, {
duration: 2000,
easing: tween.easeOut,
onFinish: function onFinish() {
LK.effects.flashScreen(0x8B0000, 1000);
score += 15000;
gold += 8000;
updateUI();
}
});
break;
case 'blackHole':
// Check if we're combining with another black hole
var adjacentBlackHoles = [];
var adjacentPositions = [[-1, 0], [1, 0], [0, -1], [0, 1]];
for (var a = 0; a < adjacentPositions.length; a++) {
var adjRow = row + adjacentPositions[a][0];
var adjCol = col + adjacentPositions[a][1];
if (adjRow >= 0 && adjRow < GRID_SIZE && adjCol >= 0 && adjCol < GRID_SIZE) {
if (grid[adjRow][adjCol] && grid[adjRow][adjCol].isSpecial && grid[adjRow][adjCol].specialType === 'blackHole') {
adjacentBlackHoles.push(grid[adjRow][adjCol]);
}
}
}
if (adjacentBlackHoles.length > 0) {
// Black hole + black hole combo: create supernova
var otherBlackHole = adjacentBlackHoles[0];
// Transform this black hole into supernova
candy.makeSpecial('supernova');
// Remove other black hole
grid[otherBlackHole.row][otherBlackHole.col] = null;
otherBlackHole.explode();
// Create spectacular combination effect
tween(candy.graphics, {
scaleX: 2.5,
scaleY: 2.5,
tint: 0xFFD700,
rotation: Math.PI * 6
}, {
duration: 1500,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Add continuous pulsing glow effect
var _pulseSuperNova = function pulseSuperNova() {
if (candy && candy.isSpecial && candy.specialType === 'supernova' && candy.parent) {
tween(candy.graphics, {
scaleX: 1.5,
scaleY: 1.5,
tint: 0xFFFF00
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(candy.graphics, {
scaleX: 1.3,
scaleY: 1.3,
tint: 0xFFFFFF
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
LK.setTimeout(_pulseSuperNova, 200);
}
});
}
});
}
};
_pulseSuperNova();
LK.effects.flashScreen(0xFFD700, 800);
}
});
break;
}
// Normal black hole: compress all candies in 8-range area into one square and explode
var blackHoleRange = 4; // 8-range means 4 cells in each direction (9x9 area total)
var candiesInRange = [];
// Collect all candies within 8-range (4 cells in each direction)
for (var r = Math.max(0, row - blackHoleRange); r <= Math.min(GRID_SIZE - 1, row + blackHoleRange); r++) {
for (var c = Math.max(0, col - blackHoleRange); c <= Math.min(GRID_SIZE - 1, col + blackHoleRange); c++) {
if (grid[r][c] && grid[r][c] !== candy) {
candiesInRange.push(grid[r][c]);
grid[r][c] = null; // Remove from grid immediately
}
}
}
// Create compression effect - move all candies to black hole center
for (var i = 0; i < candiesInRange.length; i++) {
(function (targetCandy, index) {
// Validate candy still exists before animating
if (targetCandy && targetCandy.parent) {
// Animate candy moving to black hole center
tween(targetCandy, {
x: candy.x,
y: candy.y,
scaleX: 0.1,
scaleY: 0.1,
alpha: 0.5
}, {
duration: 800 + index * 20,
// Staggered timing
easing: tween.easeIn,
onFinish: function onFinish() {
// Check if candy still exists before processing
if (targetCandy && targetCandy.parent) {
// Check if the pulled candy is special and activate it first
if (targetCandy.isSpecial) {
// Create a temporary grid position for the special candy at black hole center
var tempRow = row;
var tempCol = col;
targetCandy.row = tempRow;
targetCandy.col = tempCol;
// Activate the special candy effect
activateSpecialCandy(targetCandy);
} else {
// Explode candy with score when it reaches center
explodeCandyWithScore(targetCandy);
}
}
}
});
}
})(candiesInRange[i], i);
}
// Create visual black hole effect
tween(candy.graphics, {
scaleX: 2.0,
scaleY: 2.0,
rotation: Math.PI * 4,
alpha: 0.3
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Flash effect when compression is complete
LK.effects.flashScreen(0x000000, 300);
}
});
break;
case 'converter':
// Converter: check for adjacent candies to combine with
var adjacentPositions = [[-1, 0], [1, 0], [0, -1], [0, 1]];
var adjacentCandies = [];
for (var a = 0; a < adjacentPositions.length; a++) {
var adjRow = row + adjacentPositions[a][0];
var adjCol = col + adjacentPositions[a][1];
if (adjRow >= 0 && adjRow < GRID_SIZE && adjCol >= 0 && adjCol < GRID_SIZE) {
if (grid[adjRow][adjCol] && !grid[adjRow][adjCol].isSpecial) {
adjacentCandies.push(grid[adjRow][adjCol]);
}
}
}
if (adjacentCandies.length > 0) {
// Combine with first adjacent candy
var targetCandy = adjacentCandies[0];
var targetColor = targetCandy.type;
// Remove the target candy
grid[targetCandy.row][targetCandy.col] = null;
targetCandy.explode();
// Create the appropriate special candy based on target color
var newSpecialType;
if (targetColor === 'blue') {
newSpecialType = 'blueBomb';
} else if (targetColor === 'red') {
newSpecialType = 'redRocket';
} else if (targetColor === 'green') {
newSpecialType = 'greenPentagon';
} else if (targetColor === 'orange') {
newSpecialType = 'orangeLollipop';
} else if (targetColor === 'purple') {
newSpecialType = 'blackHole';
}
// Transform converter into the new special candy
candy.makeSpecial(newSpecialType);
// Set flag to prevent immediate activation
candy.justCreated = true;
// Create spectacular combination effect
tween(candy.graphics, {
scaleX: 2.0,
scaleY: 2.0,
tint: 0x4a90e2,
rotation: Math.PI * 2
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Flash effect to show transformation
LK.effects.flashScreen(0x4a90e2, 500);
// Add bonus score for converter combination
score += 3000;
gold += 1500;
updateUI();
LK.getSound('powerup').play();
// Remove the creation flag after animation completes
LK.setTimeout(function () {
if (candy && candy.parent) {
candy.justCreated = false;
}
}, 1000);
}
});
// Don't break here - return early to prevent converter destruction
return;
}
// No adjacent candies - converter just explodes without effect
tween(candy.graphics, {
scaleX: 1.5,
scaleY: 1.5,
tint: 0x4a90e2,
alpha: 0.5
}, {
duration: 500,
easing: tween.easeOut
});
break;
case 'vriper':
// First check for vriper + vriper combination
var adjacentVripers = [];
var adjacentPositions = [[-1, 0], [1, 0], [0, -1], [0, 1]];
for (var a = 0; a < adjacentPositions.length; a++) {
var adjRow = row + adjacentPositions[a][0];
var adjCol = col + adjacentPositions[a][1];
if (adjRow >= 0 && adjRow < GRID_SIZE && adjCol >= 0 && adjCol < GRID_SIZE) {
if (grid[adjRow][adjCol] && grid[adjRow][adjCol].isSpecial && grid[adjRow][adjCol].specialType === 'vriper') {
adjacentVripers.push(grid[adjRow][adjCol]);
}
}
}
if (adjacentVripers.length > 0) {
// Vriper + vriper combo: both disappear and create disco ball
var otherVriper = adjacentVripers[0];
// Transform this vriper into disco ball
candy.makeSpecial('discoBall');
// Remove other vriper
grid[otherVriper.row][otherVriper.col] = null;
otherVriper.explode();
// Create spectacular combination effect
tween(candy.graphics, {
scaleX: 2.0,
scaleY: 2.0,
tint: 0xFFFFFF,
rotation: Math.PI * 4
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Add continuous rotation to disco ball
var _rotateDiscoBall = function rotateDiscoBall() {
if (candy.isSpecial && candy.specialType === 'discoBall' && candy.parent) {
tween(candy.graphics, {
rotation: candy.graphics.rotation + Math.PI * 2
}, {
duration: 6000,
easing: tween.linear,
onFinish: function onFinish() {
LK.setTimeout(_rotateDiscoBall, 100);
}
});
}
};
_rotateDiscoBall();
LK.effects.flashScreen(0xFFFFFF, 800);
}
});
// Add bonus score for combination
score += 6000;
gold += 3000;
updateUI();
LK.getSound('powerup').play();
break;
}
// Vriper: can combine with any color candy to destroy all candies of that color
// Check adjacent positions for any candy (not special)
var adjacentCandies = [];
for (var a = 0; a < adjacentPositions.length; a++) {
var adjRow = row + adjacentPositions[a][0];
var adjCol = col + adjacentPositions[a][1];
if (adjRow >= 0 && adjRow < GRID_SIZE && adjCol >= 0 && adjCol < GRID_SIZE) {
if (grid[adjRow][adjCol] && !grid[adjRow][adjCol].isSpecial) {
adjacentCandies.push(grid[adjRow][adjCol]);
}
}
}
if (adjacentCandies.length > 0) {
// Combine with first adjacent candy
var targetCandy = adjacentCandies[0];
var targetColor = targetCandy.type;
// Create white circle effect that expands
tween(candy.graphics, {
scaleX: 4.0,
scaleY: 4.0,
alpha: 0.3,
tint: 0xFFFFFF
}, {
duration: 1500,
easing: tween.easeOut,
onFinish: function onFinish() {
// After white circle expansion, destroy all candies of target color
var candiesOfTargetColor = [];
for (var r = 0; r < GRID_SIZE; r++) {
for (var c = 0; c < GRID_SIZE; c++) {
if (grid[r][c] && grid[r][c].type === targetColor && grid[r][c] !== candy) {
candiesOfTargetColor.push(grid[r][c]);
grid[r][c] = null;
}
}
}
// Destroy all candies of target color with white flash effect
for (var i = 0; i < candiesOfTargetColor.length; i++) {
(function (candyToDestroy, index) {
LK.setTimeout(function () {
if (candyToDestroy && candyToDestroy.parent) {
// Flash white before exploding
tween(candyToDestroy.graphics, {
tint: 0xFFFFFF,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 200,
onFinish: function onFinish() {
explodeCandyWithScore(candyToDestroy);
}
});
}
}, index * 50);
})(candiesOfTargetColor[i], i);
}
// Create disco ball at vriper position when vriper + candy combination is complete
LK.setTimeout(function () {
if (candy && candy.parent) {
candy.makeSpecial('discoBall');
// Add creation sparkle effect
tween(candy.graphics, {
scaleX: 1.0,
scaleY: 1.0,
rotation: Math.PI,
tint: 0xFFFFFF
}, {
duration: 300,
easing: tween.bounceOut
});
}
}, candiesOfTargetColor.length * 50 + 500);
}
});
// Add massive bonus for vriper activation
score += 8000;
gold += 4000;
updateUI();
LK.effects.flashScreen(0xFFFFFF, 1000);
LK.getSound('powerup').play();
break;
}
// Normal vriper without adjacent candies - just shine
tween(candy.graphics, {
scaleX: 2.0,
scaleY: 2.0,
tint: 0xFFFFFF,
alpha: 0.8
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(candy.graphics, {
scaleX: 1.1,
scaleY: 1.1,
alpha: 1.0
}, {
duration: 500,
easing: tween.easeOut
});
}
});
break;
case 'hourglass':
// Check if we're combining with another candy first
var adjacentCandies = [];
var adjacentPositions = [[-1, 0], [1, 0], [0, -1], [0, 1]];
for (var a = 0; a < adjacentPositions.length; a++) {
var adjRow = row + adjacentPositions[a][0];
var adjCol = col + adjacentPositions[a][1];
if (adjRow >= 0 && adjRow < GRID_SIZE && adjCol >= 0 && adjCol < GRID_SIZE) {
if (grid[adjRow][adjCol] && !grid[adjRow][adjCol].isSpecial) {
adjacentCandies.push(grid[adjRow][adjCol]);
}
}
}
if (adjacentCandies.length > 0) {
// Hourglass combining with adjacent candy - cover all map with a random candy type
var targetCandy = adjacentCandies[0];
// Remove the adjacent candy
grid[targetCandy.row][targetCandy.col] = null;
targetCandy.explode();
// Create spectacular combination effect
tween(candy.graphics, {
scaleX: 3.0,
scaleY: 3.0,
tint: 0xFFD700,
rotation: Math.PI * 6
}, {
duration: 1500,
easing: tween.easeOut,
onFinish: function onFinish() {
LK.effects.flashScreen(0xFFD700, 1200);
}
});
} else {
// Normal hourglass activation
// Create hourglass visual effect
tween(candy.graphics, {
scaleX: 2.5,
scaleY: 2.5,
tint: 0xFFD700,
rotation: Math.PI * 4
}, {
duration: 1200,
easing: tween.easeOut,
onFinish: function onFinish() {
LK.effects.flashScreen(0xFFD700, 800);
}
});
}
// Hourglass: turn all candies on the map to a single random candy type with wave effect
var centerRow = candy.row;
var centerCol = candy.col;
var maxDistance = Math.max(GRID_SIZE, GRID_SIZE);
// Pick a random color for the whole map (from COLORS)
var randomColorForMap = COLORS[Math.floor(Math.random() * COLORS.length)];
var assetMap = {
'blue': 'blueCandy',
'red': 'redCandy',
'green': 'greenCandy',
'orange': 'orangeCandy',
'purple': 'purpleCandy'
};
for (var distance = 1; distance <= maxDistance; distance++) {
(function (dist) {
LK.setTimeout(function () {
// Collect all candies at this distance
var candiesAtDistance = [];
for (var r = 0; r < GRID_SIZE; r++) {
for (var c = 0; c < GRID_SIZE; c++) {
var actualDist = Math.max(Math.abs(r - centerRow), Math.abs(c - centerCol));
if (actualDist === dist && grid[r][c] && grid[r][c] !== candy) {
candiesAtDistance.push(grid[r][c]);
}
}
}
// Transform all candies at this distance to the random color
for (var i = 0; i < candiesAtDistance.length; i++) {
(function (targetCandy, index) {
if (targetCandy && targetCandy.parent) {
// Update candy type to the random color
targetCandy.type = randomColorForMap;
// Remove old graphics
targetCandy.removeChild(targetCandy.graphics);
// Create new graphics for the random color
targetCandy.graphics = targetCandy.attachAsset(assetMap[randomColorForMap], {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
});
// Reset special properties
targetCandy.isSpecial = false;
targetCandy.specialType = null;
targetCandy.isTimeless = false;
// Add transformation effect
tween(targetCandy.graphics, {
scaleX: 1.3,
scaleY: 1.3,
tint: 0xFFD700
}, {
duration: 400,
easing: tween.bounceOut,
onFinish: function onFinish() {
tween(targetCandy.graphics, {
scaleX: 0.8,
scaleY: 0.8,
tint: 0xFFFFFF
}, {
duration: 300,
easing: tween.easeOut
});
}
});
}
})(candiesAtDistance[i], i);
}
}, dist * 100); // Stagger waves outward
})(distance);
}
// Add bonus for hourglass activation
score += 8000;
gold += 4000;
updateUI();
LK.getSound('powerup').play();
break;
}
candy.explode();
grid[row][col] = null;
updateUI(); // Update UI to show earned points
LK.getSound('powerup').play();
// Drop candies to fill empty spaces after special candy activation
LK.setTimeout(function () {
dropCandies();
LK.setTimeout(function () {
processMatches();
}, 300);
}, 400);
}
// Variables for swipe detection
var dragStartX = 0;
var dragStartY = 0;
var dragCandy = null;
var isDragging = false;
var SWIPE_THRESHOLD = 80; // Minimum distance for swipe
game.down = function (x, y, obj) {
// Handle name input if active
if (game.nameInputHandler) {
game.nameInputHandler(x, y);
return;
}
// Block all input when game is won
if (gameState === 'victory') {
return; // No input allowed after victory
}
// Handle menu navigation first
if (gameState === 'menu') {
// Check start button click
var dx = x - mainMenuContainer.startButton.x;
var dy = y - mainMenuContainer.startButton.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 200) {
// Animate button press
tween(mainMenuContainer.startButton, {
scaleX: 1.8,
scaleY: 1.3
}, {
duration: 100,
onFinish: function onFinish() {
tween(mainMenuContainer.startButton, {
scaleX: 2.0,
scaleY: 1.5
}, {
duration: 100,
onFinish: function onFinish() {
startGame();
}
});
}
});
return;
}
// Check settings button click
dx = x - mainMenuContainer.settingsButton.x;
dy = y - mainMenuContainer.settingsButton.y;
distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 200) {
// Animate button press
tween(mainMenuContainer.settingsButton, {
scaleX: 1.8,
scaleY: 1.3
}, {
duration: 100,
onFinish: function onFinish() {
tween(mainMenuContainer.settingsButton, {
scaleX: 2.0,
scaleY: 1.5
}, {
duration: 100,
onFinish: function onFinish() {
showSettingsMenu();
}
});
}
});
return;
}
// Check statistics button click
dx = x - mainMenuContainer.statisticsButton.x;
dy = y - mainMenuContainer.statisticsButton.y;
distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 200) {
// Animate button press
tween(mainMenuContainer.statisticsButton, {
scaleX: 1.8,
scaleY: 1.3
}, {
duration: 100,
onFinish: function onFinish() {
tween(mainMenuContainer.statisticsButton, {
scaleX: 2.0,
scaleY: 1.5
}, {
duration: 100,
onFinish: function onFinish() {
showStatisticsMenu();
}
});
}
});
return;
}
// Check new game button click
dx = x - mainMenuContainer.newGameButton.x;
dy = y - mainMenuContainer.newGameButton.y;
distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 200) {
// Animate button press
tween(mainMenuContainer.newGameButton, {
scaleX: 1.8,
scaleY: 1.3
}, {
duration: 100,
onFinish: function onFinish() {
tween(mainMenuContainer.newGameButton, {
scaleX: 2.0,
scaleY: 1.5
}, {
duration: 100,
onFinish: function onFinish() {
// Reset current score and level when starting new game
score = 0;
level = 1;
// Start the game
startGame();
}
});
}
});
return;
}
// Check saves button click
dx = x - mainMenuContainer.savesButton.x;
dy = y - mainMenuContainer.savesButton.y;
distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 200) {
// Animate button press
tween(mainMenuContainer.savesButton, {
scaleX: 1.8,
scaleY: 1.3
}, {
duration: 100,
onFinish: function onFinish() {
tween(mainMenuContainer.savesButton, {
scaleX: 2.0,
scaleY: 1.5
}, {
duration: 100,
onFinish: function onFinish() {
showSavesMenu();
}
});
}
});
return;
}
return; // Don't process game clicks in menu state
}
if (gameState === 'settings') {
// Check back button click
var dx = x - settingsMenuContainer.backButton.x;
var dy = y - settingsMenuContainer.backButton.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 150) {
// Animate button press
tween(settingsMenuContainer.backButton, {
scaleX: 1.3,
scaleY: 1.0
}, {
duration: 100,
onFinish: function onFinish() {
tween(settingsMenuContainer.backButton, {
scaleX: 1.5,
scaleY: 1.2
}, {
duration: 100,
onFinish: function onFinish() {
showMainMenu();
}
});
}
});
return;
}
return; // Don't process game clicks in settings state
}
if (gameState === 'statistics') {
// Check back button click
var dx = x - statisticsMenuContainer.backButton.x;
var dy = y - statisticsMenuContainer.backButton.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 150) {
// Animate button press
tween(statisticsMenuContainer.backButton, {
scaleX: 1.3,
scaleY: 1.0
}, {
duration: 100,
onFinish: function onFinish() {
tween(statisticsMenuContainer.backButton, {
scaleX: 1.5,
scaleY: 1.2
}, {
duration: 100,
onFinish: function onFinish() {
showMainMenu();
}
});
}
});
return;
}
return; // Don't process game clicks in statistics state
}
if (gameState === 'saves') {
// Check back button click
var dx = x - savesMenuContainer.backButton.x;
var dy = y - savesMenuContainer.backButton.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 150) {
// Animate button press
tween(savesMenuContainer.backButton, {
scaleX: 1.3,
scaleY: 1.0
}, {
duration: 100,
onFinish: function onFinish() {
tween(savesMenuContainer.backButton, {
scaleX: 1.5,
scaleY: 1.2
}, {
duration: 100,
onFinish: function onFinish() {
showMainMenu();
}
});
}
});
return;
}
// Check save slot clicks
for (var i = 0; i < savesMenuContainer.saveSlots.length; i++) {
var slot = savesMenuContainer.saveSlots[i];
var dx = x - slot.x;
var dy = y - slot.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 150) {
// Animate slot press
tween(slot.background, {
scaleX: 1.6,
scaleY: 2.3
}, {
duration: 100,
onFinish: function onFinish() {
tween(slot.background, {
scaleX: 1.8,
scaleY: 2.5
}, {
duration: 100,
onFinish: function onFinish() {
// Handle based on saves menu mode
if (savesMenuMode === 'save') {
// Save current score to selected slot
saveGameToSlot(slot.slotIndex);
} else if (savesMenuMode === 'load') {
// Load game from selected slot
loadGameFromSlot(slot.slotIndex);
}
}
});
}
});
return;
}
}
return; // Don't process game clicks in saves state
}
// Only process game clicks when in playing state
if (gameState !== 'playing') return;
// Check for save button click
var dx = x - saveButton.x;
var dy = y - saveButton.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 150) {
// Animate button press
tween(saveButton, {
scaleX: 0.8,
scaleY: 0.5
}, {
duration: 100,
onFinish: function onFinish() {
tween(saveButton, {
scaleX: 1.0,
scaleY: 0.6
}, {
duration: 100,
onFinish: function onFinish() {
// Save game state using individual storage properties
storage.savedScore = score;
storage.savedLevel = level;
storage.savedGold = gold;
storage.savedInventory = inventory;
storage.savedHourglassCount = hourglassCount;
storage.savedComboCount = savedComboCount;
storage.savedYellowCandiesClicked = yellowCandiesClicked;
storage.savedTimestamp = Date.now();
gameStateSaved = true;
// Show save confirmation
var savedText = new Text2('Game Saved!', {
size: 60,
fill: '#00FF00'
});
savedText.anchor.set(0.5, 0.5);
savedText.x = 1024;
savedText.y = 2500;
savedText.alpha = 0;
game.addChild(savedText);
tween(savedText, {
alpha: 1
}, {
duration: 500,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(savedText, {
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
if (savedText.parent) {
savedText.parent.removeChild(savedText);
}
}
});
}, 2000);
}
});
}
});
}
});
return;
}
if (isProcessing) return;
// Reset cascade combo when user makes a new move
cascadeComboCount = 0;
lastCascadeTime = 0;
// Check for shooting star click first (secret feature)
for (var i = 0; i < starField.children.length; i++) {
var child = starField.children[i];
if (child instanceof ShootingStar) {
// Check if click is near the shooting star
var dx = x - child.x;
var dy = y - child.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 50) {
// 50px hit radius
// Activate Hidden Stars achievement tracking if not already achieved
if (!achievements.hiddenStars && !hiddenStarsActivated) {
hiddenStarsActivated = true;
hiddenStarsSequence = [];
return;
}
if (!secretMode) {
activateSecretMode();
} else {
// Return to beginning of game if already in secret mode
restartGame();
}
return;
}
}
}
// Handle secret mode ball clicks
if (secretMode) {
for (var i = 0; i < secretBalls.length; i++) {
var ball = secretBalls[i];
var dx = x - ball.x;
var dy = y - ball.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 100) {
// Ball hit radius
handleSecretBallClick(i);
return;
}
}
return; // Don't handle normal candy clicks in secret mode
}
// Handle Hidden Stars achievement sequence tracking
if (hiddenStarsActivated && !achievements.hiddenStars) {
// Check if any of the numbered balls (1-4) are clicked by checking proximity to their positions
var ballPositions = [{
x: 512,
y: 683,
number: 1
},
// Ball 1
{
x: 1536,
y: 683,
number: 2
},
// Ball 2
{
x: 512,
y: 2049,
number: 3
},
// Ball 3
{
x: 1536,
y: 2049,
number: 4
} // Ball 4
];
for (var i = 0; i < ballPositions.length; i++) {
var pos = ballPositions[i];
var dx = x - pos.x;
var dy = y - pos.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 150) {
// Hit radius for sequence tracking
hiddenStarsSequence.push(pos.number);
// Visual feedback
var feedbackText = new Text2(pos.number.toString(), {
size: 80,
fill: '#FFD700'
});
feedbackText.anchor.set(0.5, 0.5);
feedbackText.x = pos.x;
feedbackText.y = pos.y - 200;
feedbackText.alpha = 0;
game.addChild(feedbackText);
tween(feedbackText, {
alpha: 1,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 300,
onFinish: function onFinish() {
tween(feedbackText, {
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
if (feedbackText.parent) {
feedbackText.parent.removeChild(feedbackText);
}
}
});
}
});
// Check achievement after each number
checkHiddenStarsAchievement();
// Reset sequence if it gets too long or wrong
if (hiddenStarsSequence.length > 4 || hiddenStarsSequence.length === 4 && !achievements.hiddenStars) {
if (!achievements.hiddenStars) {
hiddenStarsSequence = [];
}
}
return;
}
}
}
// Handle candy selection
var candy = getCandyAt(x, y);
if (!candy) {
// Clear selection if clicking empty space
if (selectedCandy) {
selectedCandy.graphics.tint = 0xFFFFFF;
tween(selectedCandy, {
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 100
});
selectedCandy = null;
}
if (selectedEternalCandy) {
selectedEternalCandy.graphics.tint = 0xFFD700;
tween(selectedEternalCandy, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 100
});
selectedEternalCandy = null;
}
return;
}
// Check for double-click to use hourglass and create timeless Karadeniz
var currentTime = Date.now();
var isDoubleClick = currentTime - lastClickTime < DOUBLE_CLICK_THRESHOLD && lastClickedCandy === candy;
if (isDoubleClick && hourglassCount > 0 && candy && !candy.isSpecial) {
// Use hourglass to create timeless Karadeniz
hourglassCount--;
// Transform candy into timeless Karadeniz
candy.makeSpecial('expires');
candy.isTimeless = true;
candy.timelessHealth = 40; // Starts with 40 health
candy.maxTimelessHealth = 40;
// Add to timeless tracking array
timelessKaradenizCandies.push(candy);
// Create transformation effect
tween(candy.graphics, {
scaleX: 1.5,
scaleY: 1.5,
tint: 0xFF4500,
rotation: Math.PI * 2
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
// Start cracking effect animation
startCrackingEffect(candy);
}
});
// Show timeless creation notification
var timelessNotification = new Text2('TIMELESS KARADENIZ CREATED!', {
size: 70,
fill: '#FF4500'
});
timelessNotification.anchor.set(0.5, 0.5);
timelessNotification.x = 1024;
timelessNotification.y = 1200;
timelessNotification.alpha = 0;
game.addChild(timelessNotification);
tween(timelessNotification, {
alpha: 1,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 500,
easing: tween.bounceOut,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(timelessNotification, {
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
if (timelessNotification.parent) {
timelessNotification.parent.removeChild(timelessNotification);
}
}
});
}, 2500);
}
});
updateUI();
LK.getSound('powerup').play();
// Reset click tracking
lastClickTime = 0;
lastClickedCandy = null;
return;
}
// Black hole click tracking for void creation
if (candy && candy.isSpecial && candy.specialType === 'blackHole') {
var key = getGridKey(candy.row, candy.col);
if (!blackHoleClickCounts[key]) blackHoleClickCounts[key] = 0;
blackHoleClickCounts[key]++;
// Visual feedback for click count
var clickText = new Text2(blackHoleClickCounts[key] + '/3', {
size: 60,
fill: '#6e00ff'
});
clickText.anchor.set(0.5, 0.5);
clickText.x = candy.x;
clickText.y = candy.y - 120;
clickText.alpha = 0;
game.addChild(clickText);
tween(clickText, {
alpha: 1,
scaleX: 1.3,
scaleY: 1.3,
y: candy.y - 150
}, {
duration: 200,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(clickText, {
alpha: 0,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 200,
onFinish: function onFinish() {
if (clickText.parent) clickText.parent.removeChild(clickText);
}
});
}, 600);
}
});
// On 3rd click, create void and remove 2 hourglasses
if (blackHoleClickCounts[key] === 3) {
if (hourglassCount >= 2) {
hourglassCount -= 2;
// Remove black hole and create void
if (candy.parent) candy.parent.removeChild(candy);
grid[candy.row][candy.col] = null;
createVoidAt(candy.row, candy.col);
// Show void creation notification
var voidText = new Text2('VOID CREATED!', {
size: 80,
fill: '#6e00ff'
});
voidText.anchor.set(0.5, 0.5);
voidText.x = 1024;
voidText.y = 1366;
voidText.alpha = 0;
game.addChild(voidText);
tween(voidText, {
alpha: 1,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 400,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(voidText, {
alpha: 0
}, {
duration: 400,
onFinish: function onFinish() {
if (voidText.parent) voidText.parent.removeChild(voidText);
}
});
}, 1200);
}
});
updateUI();
} else {
// Not enough hourglasses
var warnText = new Text2('Need 2 Hourglasses!', {
size: 60,
fill: '#FF0000'
});
warnText.anchor.set(0.5, 0.5);
warnText.x = 1024;
warnText.y = 1366;
warnText.alpha = 0;
game.addChild(warnText);
tween(warnText, {
alpha: 1
}, {
duration: 300,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(warnText, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
if (warnText.parent) warnText.parent.removeChild(warnText);
}
});
}, 1000);
}
});
}
blackHoleClickCounts[key] = 0;
return;
}
// On 5th click, transform into void directly
if (blackHoleClickCounts[key] === 5) {
// Transform black hole into void directly
candy.makeSpecial('void');
candy.specialType = 'void';
candy.type = 'void';
candy.voidComboType = null;
candy.voidComboActive = false;
// Replace graphics with void look
candy.removeChild(candy.graphics);
candy.graphics = candy.attachAsset('purpleCandy', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
});
tween(candy.graphics, {
tint: 0x6e00ff,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 400,
onFinish: function onFinish() {
tween(candy.graphics, {
tint: 0x9013fe,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 300
});
}
});
// Add to void positions tracking
voidPositions.push({
row: candy.row,
col: candy.col
});
// Show void transformation notification
var voidText = new Text2('BLACK HOLE → VOID!', {
size: 80,
fill: '#6e00ff'
});
voidText.anchor.set(0.5, 0.5);
voidText.x = 1024;
voidText.y = 1366;
voidText.alpha = 0;
game.addChild(voidText);
tween(voidText, {
alpha: 1,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 400,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(voidText, {
alpha: 0
}, {
duration: 400,
onFinish: function onFinish() {
if (voidText.parent) voidText.parent.removeChild(voidText);
}
});
}, 1200);
}
});
blackHoleClickCounts[key] = 0;
return;
}
// On 7th click, transform void into infinite void
if (blackHoleClickCounts[key] === 7) {
// Transform void into infinite void
candy.isInfiniteVoid = true;
candy.specialType = 'infiniteVoid';
// Enhanced visual effects for infinite void
candy.removeChild(candy.graphics);
candy.graphics = candy.attachAsset('purpleCandy', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
});
tween(candy.graphics, {
tint: 0x4B0082,
scaleX: 1.5,
scaleY: 1.5,
rotation: Math.PI * 2
}, {
duration: 600,
onFinish: function onFinish() {
// Add continuous swirling effect for infinite void
var _swirl = function swirl() {
if (candy && candy.isInfiniteVoid && candy.parent) {
tween(candy.graphics, {
tint: 0x8A2BE2,
scaleX: 1.7,
scaleY: 1.7,
rotation: candy.graphics.rotation + Math.PI * 2
}, {
duration: 1500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(candy.graphics, {
tint: 0x4B0082,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 1500,
easing: tween.easeInOut,
onFinish: function onFinish() {
LK.setTimeout(_swirl, 100);
}
});
}
});
}
};
_swirl();
}
});
// Show infinite void transformation notification
var infiniteVoidText = new Text2('SONSUZ BOŞLUK!', {
size: 90,
fill: '#8A2BE2'
});
infiniteVoidText.anchor.set(0.5, 0.5);
infiniteVoidText.x = 1024;
infiniteVoidText.y = 1366;
infiniteVoidText.alpha = 0;
game.addChild(infiniteVoidText);
tween(infiniteVoidText, {
alpha: 1,
scaleX: 1.4,
scaleY: 1.4,
rotation: 0.1
}, {
duration: 600,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(infiniteVoidText, {
alpha: 0
}, {
duration: 600,
onFinish: function onFinish() {
if (infiniteVoidText.parent) infiniteVoidText.parent.removeChild(infiniteVoidText);
}
});
}, 1500);
}
});
LK.effects.flashScreen(0x8A2BE2, 1000);
blackHoleClickCounts[key] = 0;
return;
}
}
// Update click tracking for double-click detection
lastClickTime = currentTime;
lastClickedCandy = candy;
// Check if clicking on yellow candy for hourglass system (orange candies)
if (candy && candy.type === 'orange') {
// Create unique identifier for this candy position
var candyId = candy.row + '_' + candy.col + '_' + candy.type;
// Check if this yellow candy hasn't been clicked yet
var alreadyClicked = false;
for (var i = 0; i < yellowCandiesClicked.length; i++) {
if (yellowCandiesClicked[i] === candyId) {
alreadyClicked = true;
break;
}
}
// If candy hasn't been clicked yet, mark it as clicked
if (!alreadyClicked) {
yellowCandiesClicked.push(candyId);
// Check if we have 4 yellow candies clicked to create hourglass
if (yellowCandiesClicked.length >= 4) {
// Create hourglass
hourglassCount++;
// Reset yellow candies counter
yellowCandiesClicked = [];
// Save combo count for later use
savedComboCount = cascadeComboCount;
// Show hourglass creation notification
var hourglassNotification = new Text2('HOURGLASS CREATED!', {
size: 80,
fill: '#FFD700'
});
hourglassNotification.anchor.set(0.5, 0.5);
hourglassNotification.x = 1024;
hourglassNotification.y = 1200;
hourglassNotification.alpha = 0;
game.addChild(hourglassNotification);
tween(hourglassNotification, {
alpha: 1,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 500,
easing: tween.bounceOut,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(hourglassNotification, {
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
if (hourglassNotification.parent) {
hourglassNotification.parent.removeChild(hourglassNotification);
}
}
});
}, 2000);
}
});
updateUI();
LK.getSound('powerup').play();
}
}
}
// Check if clicking on a ball (any candy) for Small Collector achievement
if (candy && !achievements.smallCollector) {
// Count total balls on first click if not already set
if (totalBallsToClick === 0) {
for (var row = 0; row < GRID_SIZE; row++) {
for (var col = 0; col < GRID_SIZE; col++) {
if (grid[row][col]) {
totalBallsToClick++;
}
}
}
}
// Create unique identifier for this ball position
var ballId = candy.row + '_' + candy.col;
// Check if this ball hasn't been clicked small yet
var alreadyClickedSmall = false;
for (var i = 0; i < ballsClickedSmall.length; i++) {
if (ballsClickedSmall[i] === ballId) {
alreadyClickedSmall = true;
break;
}
}
// If ball hasn't been clicked small yet, mark it as clicked small
if (!alreadyClickedSmall) {
ballsClickedSmall.push(ballId);
// Check if achievement should be unlocked
checkSmallCollectorAchievement();
}
}
// Add shrinking animation when candy is clicked
tween(candy, {
scaleX: 0.6,
scaleY: 0.6
}, {
duration: 150,
easing: tween.easeIn,
onFinish: function onFinish() {
tween(candy, {
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 150,
easing: tween.bounceOut
});
}
});
// Handle eternal candy clicks first
if (isEternalCandy(candy)) {
if (selectedEternalCandy === null) {
// Select eternal candy
selectedEternalCandy = candy;
candy.graphics.tint = 0xFFFFFF;
tween(candy, {
scaleX: 1.6,
scaleY: 1.6
}, {
duration: 150
});
// Show instruction text
var instructionText = new Text2('Herhangi bir şekere tıklayın!', {
size: 60,
fill: '#FFD700'
});
instructionText.anchor.set(0.5, 0.5);
instructionText.x = 1024;
instructionText.y = 1100;
instructionText.alpha = 0;
game.addChild(instructionText);
tween(instructionText, {
alpha: 1
}, {
duration: 300,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(instructionText, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
if (instructionText.parent) instructionText.parent.removeChild(instructionText);
}
});
}, 2000);
}
});
return;
} else if (selectedEternalCandy === candy) {
// Deselect eternal candy
selectedEternalCandy.graphics.tint = 0xFFD700;
tween(selectedEternalCandy, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 100
});
selectedEternalCandy = null;
return;
}
}
// If eternal candy is selected and we click another candy, teleport eternal candy there
if (selectedEternalCandy && candy !== selectedEternalCandy) {
// Store old position
var oldRow = selectedEternalCandy.row;
var oldCol = selectedEternalCandy.col;
var newRow = candy.row;
var newCol = candy.col;
// Remove candy at target position
if (candy.parent) {
candy.parent.removeChild(candy);
}
grid[newRow][newCol] = null;
// Remove eternal candy from old position
grid[oldRow][oldCol] = null;
// Place eternal candy at new position
grid[newRow][newCol] = selectedEternalCandy;
selectedEternalCandy.row = newRow;
selectedEternalCandy.col = newCol;
// Animate teleportation with spectacular effect
tween(selectedEternalCandy, {
x: GRID_START_X + newCol * CELL_SIZE + CELL_SIZE / 2,
y: GRID_START_Y + newRow * CELL_SIZE + CELL_SIZE / 2,
scaleX: 2.0,
scaleY: 2.0,
tint: 0xFFFFFF,
alpha: 0.5
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(selectedEternalCandy, {
scaleX: 1.3,
scaleY: 1.3,
tint: 0xFFD700,
alpha: 1.0
}, {
duration: 300,
easing: tween.easeOut
});
}
});
// Update eternal candy position tracking
for (var i = 0; i < eternalCandies.length; i++) {
if (eternalCandies[i].row === oldRow && eternalCandies[i].col === oldCol) {
eternalCandies[i].row = newRow;
eternalCandies[i].col = newCol;
break;
}
}
// Create teleportation effect
LK.effects.flashScreen(0xFFD700, 600);
// Reset selection
selectedEternalCandy.graphics.tint = 0xFFD700;
selectedEternalCandy = null;
// Process matches after teleportation
LK.setTimeout(function () {
// Check for matches at new position
processMatches();
}, 500);
return;
}
// Click-to-select then click-to-swap mode
if (selectedCandy === null) {
// Check if player has reached 3 consecutive combos and should activate hourglass
if (hourglassCount > 0 && cascadeComboCount >= 3) {
// Use hourglass to maintain super combo level
hourglassCount--;
// Keep combo at super combo level (level 3)
cascadeComboCount = 3;
savedComboCount = 3;
lastCascadeTime = Date.now();
// Show hourglass activation notification
var hourglassUseNotification = new Text2('HOURGLASS ACTIVATED! SUPER COMBO MAINTAINED!', {
size: 65,
fill: '#FFD700'
});
hourglassUseNotification.anchor.set(0.5, 0.5);
hourglassUseNotification.x = 1024;
hourglassUseNotification.y = 1200;
hourglassUseNotification.alpha = 0;
game.addChild(hourglassUseNotification);
tween(hourglassUseNotification, {
alpha: 1,
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 500,
easing: tween.bounceOut,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(hourglassUseNotification, {
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
if (hourglassUseNotification.parent) {
hourglassUseNotification.parent.removeChild(hourglassUseNotification);
}
}
});
}, 2000);
}
});
// Show current combo display
if (cascadeComboCount >= 1 && cascadeComboCount <= 7) {
showCascadeComboDisplay(cascadeComboCount);
}
updateUI();
LK.getSound('powerup').play();
}
// Check if clicking on a supernova - activate it directly (but not if just created)
if (candy.isSpecial && candy.specialType === 'supernova' && !candy.justCreated) {
isProcessing = true;
activateSpecialCandy(candy);
return;
}
// First click - select candy
selectedCandy = candy;
// Visual feedback for selected candy
candy.graphics.tint = 0x00FF00; // Green tint for selection
tween(candy, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 100
});
} else if (selectedCandy === candy) {
// Clicking same candy - deselect
selectedCandy.graphics.tint = 0xFFFFFF;
tween(selectedCandy, {
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 100
});
selectedCandy = null;
} else {
// Second click - try to swap with selected candy or activate special
var tempSelectedCandy = selectedCandy;
// Check if clicking on a supernova - activate it directly (but not if just created)
if (candy.isSpecial && candy.specialType === 'supernova' && !candy.justCreated) {
selectedCandy.graphics.tint = 0xFFFFFF;
tween(selectedCandy, {
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 100
});
selectedCandy = null;
isProcessing = true;
activateSpecialCandy(candy);
return;
}
// Check if candies are adjacent
var dx = Math.abs(tempSelectedCandy.col - candy.col);
var dy = Math.abs(tempSelectedCandy.row - candy.row);
if (dx + dy === 1) {
// Adjacent candies - perform swap
isProcessing = true;
// Reset visual effects
tempSelectedCandy.graphics.tint = 0xFFFFFF;
tween(tempSelectedCandy, {
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 100
});
selectedCandy = null;
if (swapCandies(tempSelectedCandy, candy)) {
LK.setTimeout(function () {
// Check if swap creates matches
var matches1 = checkMatch(tempSelectedCandy.row, tempSelectedCandy.col);
var matches2 = checkMatch(candy.row, candy.col);
if (matches1.length >= 3 || matches2.length >= 3 || tempSelectedCandy.isSpecial && tempSelectedCandy.specialType !== 'supernova' || candy.isSpecial && candy.specialType !== 'supernova') {
// Valid move
if (tempSelectedCandy.isSpecial && tempSelectedCandy.specialType !== 'supernova' && !tempSelectedCandy.justCreated) {
activateSpecialCandy(tempSelectedCandy);
}
if (candy.isSpecial && candy.specialType !== 'supernova' && !candy.justCreated) {
activateSpecialCandy(candy);
}
LK.setTimeout(function () {
processMatches();
}, 200);
} else {
// Invalid move, swap back with animation
swapCandies(tempSelectedCandy, candy);
isProcessing = false;
}
}, 250);
}
} else {
// Not adjacent - switch selection to new candy
tempSelectedCandy.graphics.tint = 0xFFFFFF;
tween(tempSelectedCandy, {
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 100
});
selectedCandy = candy;
candy.graphics.tint = 0x00FF00;
tween(candy, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 100
});
}
}
// Start drag tracking for drag mode (fallback)
dragStartX = x;
dragStartY = y;
dragCandy = candy;
isDragging = false;
};
game.move = function (x, y, obj) {
// Block all movement when game is won
if (gameState === 'victory') {
return; // No movement allowed after victory
}
if (isProcessing || !dragCandy) return;
var deltaX = x - dragStartX;
var deltaY = y - dragStartY;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
// Check if we've moved far enough to start dragging
if (distance > SWIPE_THRESHOLD && !isDragging) {
isDragging = true;
// Add visual feedback - slightly scale up the dragged candy
tween(dragCandy, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 100
});
dragCandy.graphics.tint = 0xFFFF00; // Yellow tint during drag
}
};
game.up = function (x, y, obj) {
// Block all up events when game is won
if (gameState === 'victory') {
return; // No up events allowed after victory
}
if (isProcessing || !dragCandy) return;
var deltaX = x - dragStartX;
var deltaY = y - dragStartY;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
// Reset visual effects
dragCandy.graphics.tint = 0xFFFFFF;
tween(dragCandy, {
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 100
});
if (distance > SWIPE_THRESHOLD) {
// Determine swipe direction
var targetCandy = null;
var absX = Math.abs(deltaX);
var absY = Math.abs(deltaY);
if (absX > absY) {
// Horizontal swipe
if (deltaX > 0) {
// Swipe right
if (dragCandy.col < GRID_SIZE - 1) {
targetCandy = grid[dragCandy.row][dragCandy.col + 1];
}
} else {
// Swipe left
if (dragCandy.col > 0) {
targetCandy = grid[dragCandy.row][dragCandy.col - 1];
}
}
} else {
// Vertical swipe
if (deltaY > 0) {
// Swipe down
if (dragCandy.row < GRID_SIZE - 1) {
targetCandy = grid[dragCandy.row + 1][dragCandy.col];
}
} else {
// Swipe up
if (dragCandy.row > 0) {
targetCandy = grid[dragCandy.row - 1][dragCandy.col];
}
}
}
// If we have a valid target, try to swap
if (targetCandy) {
var tempSelectedCandy = dragCandy;
selectedCandy = null;
isProcessing = true;
if (swapCandies(tempSelectedCandy, targetCandy)) {
LK.setTimeout(function () {
// Check if swap creates matches
var matches1 = checkMatch(tempSelectedCandy.row, tempSelectedCandy.col);
var matches2 = checkMatch(targetCandy.row, targetCandy.col);
if (matches1.length >= 3 || matches2.length >= 3 || tempSelectedCandy.isSpecial && tempSelectedCandy.specialType !== 'supernova' || targetCandy.isSpecial && targetCandy.specialType !== 'supernova') {
// Valid move
if (tempSelectedCandy.isSpecial && tempSelectedCandy.specialType !== 'supernova' && !tempSelectedCandy.justCreated) {
activateSpecialCandy(tempSelectedCandy);
}
if (targetCandy.isSpecial && targetCandy.specialType !== 'supernova' && !targetCandy.justCreated) {
activateSpecialCandy(targetCandy);
}
LK.setTimeout(function () {
processMatches();
}, 200);
} else {
// Invalid move, swap back with animation
swapCandies(tempSelectedCandy, targetCandy);
isProcessing = false;
}
}, 250);
}
}
}
// Reset drag state
dragCandy = null;
dragStartX = 0;
dragStartY = 0;
isDragging = false;
selectedCandy = null;
};
function activateSecretMode() {
secretMode = true;
secretClickSequence = [];
updateUI();
// Backup current grid state
secretGridBackup = [];
for (var row = 0; row < GRID_SIZE; row++) {
secretGridBackup[row] = [];
for (var col = 0; col < GRID_SIZE; col++) {
secretGridBackup[row][col] = grid[row][col];
}
}
// Clear everything from screen
for (var row = 0; row < GRID_SIZE; row++) {
for (var col = 0; col < GRID_SIZE; col++) {
if (grid[row][col] && grid[row][col].parent) {
grid[row][col].parent.removeChild(grid[row][col]);
}
grid[row][col] = null;
}
}
// Hide UI elements
tween(scoreText, {
alpha: 0
}, {
duration: 300
});
tween(levelText, {
alpha: 0
}, {
duration: 300
});
tween(goldText, {
alpha: 0
}, {
duration: 300
});
tween(comboText, {
alpha: 0
}, {
duration: 300
});
tween(progressBarBg, {
alpha: 0
}, {
duration: 300
});
// Create 4 secret balls in sequence positions
createSecretBalls();
}
function createSecretBalls() {
secretBalls = [];
var positions = [{
x: 512,
y: 683
},
// Top left quadrant
{
x: 1536,
y: 683
},
// Top right quadrant
{
x: 512,
y: 2049
},
// Bottom left quadrant
{
x: 1536,
y: 2049
} // Bottom right quadrant
];
for (var i = 0; i < 4; i++) {
var ball = LK.getAsset('discoBall', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.0,
scaleY: 1.0,
x: positions[i].x,
y: positions[i].y
});
game.addChild(ball);
secretBalls.push(ball);
// Add number text on top of each ball
var numberText = new Text2((i + 1).toString(), {
size: 120,
fill: '#FFFFFF'
});
numberText.anchor.set(0.5, 0.5);
numberText.x = positions[i].x;
numberText.y = positions[i].y - 150; // Position above the ball
game.addChild(numberText);
ball.numberText = numberText; // Store reference for cleanup
// Add continuous rotation
var _rotateBall = function rotateBall(ballRef) {
tween(ballRef, {
rotation: ballRef.rotation + Math.PI * 2
}, {
duration: 3000,
easing: tween.linear,
onFinish: function onFinish() {
if (secretMode) {
_rotateBall(ballRef);
}
}
});
};
_rotateBall(ball);
}
// Create black hole in center
var blackHole = LK.getAsset('blackHole', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.0,
scaleY: 1.0,
x: 1024,
// Center of screen
y: 1366 // Center of screen
});
game.addChild(blackHole);
secretBalls.push(blackHole); // Add to secretBalls for cleanup
// Add pulsing animation to black hole
var _pulseBlackHole = function pulseBlackHole() {
tween(blackHole, {
scaleX: 1.3,
scaleY: 1.3,
alpha: 0.7
}, {
duration: 1500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(blackHole, {
scaleX: 1.0,
scaleY: 1.0,
alpha: 1.0
}, {
duration: 1500,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (secretMode) {
_pulseBlackHole();
}
}
});
}
});
};
_pulseBlackHole();
}
function handleSecretBallClick(ballIndex) {
secretClickSequence.push(ballIndex);
// Flash the clicked ball
var ball = secretBalls[ballIndex];
tween(ball, {
tint: 0xFFFFFF,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 200,
onFinish: function onFinish() {
tween(ball, {
tint: 0xFFFFFF,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 200
});
}
});
// Check if sequence is correct: 1st ball, 1st ball, 1st ball, 3rd ball (indices 0,0,0,2)
if (secretClickSequence.length >= 4) {
if (secretClickSequence[0] === 0 && secretClickSequence[1] === 0 && secretClickSequence[2] === 0 && secretClickSequence[3] === 2) {
// Correct sequence - restore game with special candies
restoreGameWithSpecialCandies();
} else {
// Wrong sequence - reset
secretClickSequence = [];
}
}
}
function restoreGameWithSpecialCandies() {
// Remove secret balls and their number texts
for (var i = 0; i < secretBalls.length; i++) {
if (secretBalls[i].parent) {
secretBalls[i].parent.removeChild(secretBalls[i]);
}
// Remove the number text as well
if (secretBalls[i].numberText && secretBalls[i].numberText.parent) {
secretBalls[i].numberText.parent.removeChild(secretBalls[i].numberText);
}
}
secretBalls = [];
// Restore grid with only special candies
for (var row = 0; row < GRID_SIZE; row++) {
for (var col = 0; col < GRID_SIZE; col++) {
var specialTypes = ['discoBall', 'redRocket', 'blueBomb', 'blackHole', 'supernova', 'expires', 'writerpir', 'vriper', 'converter'];
var randomSpecialType = specialTypes[Math.floor(Math.random() * specialTypes.length)];
// Create candy with original color but make it special
var originalColor = COLORS[Math.floor(Math.random() * COLORS.length)];
var candy = new Candy(originalColor, row, col);
candy.x = GRID_START_X + col * CELL_SIZE + CELL_SIZE / 2;
candy.y = GRID_START_Y + row * CELL_SIZE + CELL_SIZE / 2;
// Make it special immediately
candy.makeSpecial(randomSpecialType);
grid[row][col] = candy;
game.addChild(candy);
}
}
// Show UI elements again
tween(scoreText, {
alpha: 1
}, {
duration: 300
});
tween(levelText, {
alpha: 1
}, {
duration: 300
});
tween(goldText, {
alpha: 1
}, {
duration: 300
});
tween(progressBarBg, {
alpha: 1
}, {
duration: 300
});
// Set unlimited gold for test mode
gold = 999999999;
storage.gold = gold;
updateUI();
// Set 20x score multiplier for matches
comboMultiplier = 20;
showComboDisplay();
// Activate special candy spawning mode
onlySpecialCandies = true;
secretMode = false;
isProcessing = false;
}
function restartGame() {
// Reset all game variables to initial state
score = 0;
level = 1;
gold = 0;
storage.gold = gold;
inventory = {};
storage.inventory = inventory;
isProcessing = false;
comboMultiplier = 1;
selectedCandy = null;
// Reset secret feature variables
secretMode = false;
secretBalls = [];
secretClickSequence = [];
secretGridBackup = null;
onlySpecialCandies = false;
// Clear all secret balls and their number texts
for (var i = 0; i < secretBalls.length; i++) {
if (secretBalls[i].parent) {
secretBalls[i].parent.removeChild(secretBalls[i]);
}
// Remove the number text as well
if (secretBalls[i].numberText && secretBalls[i].numberText.parent) {
secretBalls[i].numberText.parent.removeChild(secretBalls[i].numberText);
}
}
secretBalls = [];
// Clear current grid completely
for (var row = 0; row < GRID_SIZE; row++) {
for (var col = 0; col < GRID_SIZE; col++) {
if (grid[row][col] && grid[row][col].parent) {
grid[row][col].parent.removeChild(grid[row][col]);
}
grid[row][col] = null;
}
}
// Show UI elements again
tween(scoreText, {
alpha: 1
}, {
duration: 300
});
tween(levelText, {
alpha: 1
}, {
duration: 300
});
tween(goldText, {
alpha: 1
}, {
duration: 300
});
tween(comboText, {
alpha: 0
}, {
duration: 300
});
tween(progressBarBg, {
alpha: 1
}, {
duration: 300
});
// Reset progress bar
progressBarFill.scaleX = 0;
// Reinitialize grid with fresh candies
initializeGrid();
removeInitialMatches();
// Update UI to show reset values
updateUI();
}
function returnToNormalGame() {
// Remove secret balls and their number texts
for (var i = 0; i < secretBalls.length; i++) {
if (secretBalls[i].parent) {
secretBalls[i].parent.removeChild(secretBalls[i]);
}
// Remove the number text as well
if (secretBalls[i].numberText && secretBalls[i].numberText.parent) {
secretBalls[i].numberText.parent.removeChild(secretBalls[i].numberText);
}
}
secretBalls = [];
// Clear current grid completely before restoring
for (var row = 0; row < GRID_SIZE; row++) {
for (var col = 0; col < GRID_SIZE; col++) {
if (grid[row][col] && grid[row][col].parent) {
grid[row][col].parent.removeChild(grid[row][col]);
}
grid[row][col] = null;
}
}
// Restore original grid state from backup
for (var row = 0; row < GRID_SIZE; row++) {
for (var col = 0; col < GRID_SIZE; col++) {
if (secretGridBackup && secretGridBackup[row] && secretGridBackup[row][col]) {
var originalCandy = secretGridBackup[row][col];
originalCandy.x = GRID_START_X + col * CELL_SIZE + CELL_SIZE / 2;
originalCandy.y = GRID_START_Y + row * CELL_SIZE + CELL_SIZE / 2;
grid[row][col] = originalCandy;
game.addChild(originalCandy);
}
}
}
// Show UI elements again
tween(scoreText, {
alpha: 1
}, {
duration: 300
});
tween(levelText, {
alpha: 1
}, {
duration: 300
});
tween(goldText, {
alpha: 1
}, {
duration: 300
});
tween(progressBarBg, {
alpha: 1
}, {
duration: 300
});
// Reset to normal game state
comboMultiplier = 1;
showComboDisplay();
onlySpecialCandies = false;
secretMode = false;
isProcessing = false;
secretGridBackup = null;
}
// Create save button
var saveButton = LK.getAsset('greenCandy', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.0,
scaleY: 0.6
});
saveButton.x = 1024;
saveButton.y = 2600;
gameContainer.addChild(saveButton);
var saveButtonText = new Text2('SAVE GAME', {
size: 50,
fill: '#FFFFFF'
});
saveButtonText.anchor.set(0.5, 0.5);
saveButtonText.x = 1024;
saveButtonText.y = 2600;
gameContainer.addChild(saveButtonText);
// Try to load saved game state on startup
LK.setTimeout(function () {
if (storage.savedScore !== undefined) {
score = storage.savedScore || 0;
level = storage.savedLevel || 1;
gold = storage.savedGold || 0;
inventory = storage.savedInventory || {};
hourglassCount = storage.savedHourglassCount || 0;
savedComboCount = storage.savedComboCount || 0;
yellowCandiesClicked = storage.savedYellowCandiesClicked || [];
storage.gold = gold;
storage.inventory = inventory;
updateUI();
gameStateSaved = true;
// Show loaded message
var loadedText = new Text2('Game Loaded!', {
size: 60,
fill: '#00FF00'
});
loadedText.anchor.set(0.5, 0.5);
loadedText.x = 1024;
loadedText.y = 2500;
loadedText.alpha = 0;
game.addChild(loadedText);
tween(loadedText, {
alpha: 1
}, {
duration: 500,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(loadedText, {
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
if (loadedText.parent) {
loadedText.parent.removeChild(loadedText);
}
}
});
}, 2000);
}
});
}
// Load achievements from storage
if (storage.smallCollectorAchieved) {
achievements.smallCollector = true;
}
if (storage.hiddenStarsAchieved) {
achievements.hiddenStars = true;
}
if (storage.leaguesAchieved) {
achievements.leagues = true;
}
if (storage.universeAchieved) {
achievements.universe = true;
}
}, 1000);
// Menu navigation functions
function showMainMenu() {
gameState = 'menu';
// Show main menu
mainMenuContainer.alpha = 1;
// Hide other menus and game
if (settingsMenuContainer) settingsMenuContainer.alpha = 0;
if (statisticsMenuContainer) statisticsMenuContainer.alpha = 0;
if (savesMenuContainer) savesMenuContainer.alpha = 0;
if (gameContainer) gameContainer.alpha = 0;
}
function showSettingsMenu() {
gameState = 'settings';
// Hide main menu
mainMenuContainer.alpha = 0;
// Show settings menu with animation
tween(settingsMenuContainer, {
alpha: 1
}, {
duration: 300,
easing: tween.easeOut
});
}
function showStatisticsMenu() {
gameState = 'statistics';
// Hide main menu
mainMenuContainer.alpha = 0;
// Show statistics menu with animation
tween(statisticsMenuContainer, {
alpha: 1
}, {
duration: 300,
easing: tween.easeOut
});
}
function showSavesMenu() {
gameState = 'saves';
savesMenuMode = 'save';
// Hide main menu
mainMenuContainer.alpha = 0;
// Refresh saves menu to show current data
refreshSavesMenu();
// Show saves menu with animation
tween(savesMenuContainer, {
alpha: 1
}, {
duration: 300,
easing: tween.easeOut
});
}
function showSavesMenuForLoad() {
gameState = 'saves';
savesMenuMode = 'load';
// Hide main menu
mainMenuContainer.alpha = 0;
// Refresh saves menu to show current data
refreshSavesMenu();
// Show saves menu with animation
tween(savesMenuContainer, {
alpha: 1
}, {
duration: 300,
easing: tween.easeOut
});
}
function saveGameToSlot(slotIndex) {
// Save current game state to the selected slot using individual storage properties
var slotPrefix = 'saveSlot' + (slotIndex + 1) + '_';
storage[slotPrefix + 'score'] = score;
storage[slotPrefix + 'level'] = level;
storage[slotPrefix + 'gold'] = gold;
storage[slotPrefix + 'hourglassCount'] = hourglassCount;
storage[slotPrefix + 'savedComboCount'] = savedComboCount;
storage[slotPrefix + 'timestamp'] = Date.now();
// Save arrays as individual indexed items since storage doesn't support nested objects
storage[slotPrefix + 'yellowCandiesClickedCount'] = yellowCandiesClicked.length;
for (var i = 0; i < yellowCandiesClicked.length; i++) {
storage[slotPrefix + 'yellowCandiesClicked_' + i] = yellowCandiesClicked[i];
}
// Mark slot as having saved data
storage[slotPrefix + 'hasSave'] = true;
// Show save confirmation
var savedText = new Text2('Slot ' + (slotIndex + 1) + ' Kaydedildi!', {
size: 70,
fill: '#00FF00'
});
savedText.anchor.set(0.5, 0.5);
savedText.x = 1024;
savedText.y = 2200;
savedText.alpha = 0;
game.addChild(savedText);
tween(savedText, {
alpha: 1
}, {
duration: 500,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(savedText, {
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
if (savedText.parent) {
savedText.parent.removeChild(savedText);
}
}
});
}, 2000);
}
});
// Refresh the saves menu to show updated slot
refreshSavesMenu();
}
function loadGameFromSlot(slotIndex) {
// Load game state from the selected slot using individual storage properties
var slotPrefix = 'saveSlot' + (slotIndex + 1) + '_';
var hasSave = storage[slotPrefix + 'hasSave'];
if (!hasSave) {
// Show message that slot is empty
var emptySlotText = new Text2('Bu slot boş!', {
size: 70,
fill: '#FF0000'
});
emptySlotText.anchor.set(0.5, 0.5);
emptySlotText.x = 1024;
emptySlotText.y = 2200;
emptySlotText.alpha = 0;
game.addChild(emptySlotText);
tween(emptySlotText, {
alpha: 1
}, {
duration: 500,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(emptySlotText, {
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
if (emptySlotText.parent) {
emptySlotText.parent.removeChild(emptySlotText);
}
}
});
}, 2000);
}
});
return;
}
// Load the saved game state
score = storage[slotPrefix + 'score'] || 0;
level = storage[slotPrefix + 'level'] || 1;
gold = storage[slotPrefix + 'gold'] || 0;
hourglassCount = storage[slotPrefix + 'hourglassCount'] || 0;
savedComboCount = storage[slotPrefix + 'savedComboCount'] || 0;
// Load yellow candies clicked array
yellowCandiesClicked = [];
var yellowCandiesCount = storage[slotPrefix + 'yellowCandiesClickedCount'] || 0;
for (var i = 0; i < yellowCandiesCount; i++) {
var candyId = storage[slotPrefix + 'yellowCandiesClicked_' + i];
if (candyId) {
yellowCandiesClicked.push(candyId);
}
}
// Save gold to storage
storage.gold = gold;
// Show load confirmation
var loadedText = new Text2('Slot ' + (slotIndex + 1) + ' Yüklendi!', {
size: 70,
fill: '#00FF00'
});
loadedText.anchor.set(0.5, 0.5);
loadedText.x = 1024;
loadedText.y = 2200;
loadedText.alpha = 0;
game.addChild(loadedText);
tween(loadedText, {
alpha: 1
}, {
duration: 500,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(loadedText, {
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
if (loadedText.parent) {
loadedText.parent.removeChild(loadedText);
}
}
});
}, 2000);
}
});
// Start the game with loaded state
LK.setTimeout(function () {
startGame();
}, 1500);
}
function refreshSavesMenu() {
// Remove existing saves menu and recreate it with updated data
if (savesMenuContainer && savesMenuContainer.parent) {
savesMenuContainer.parent.removeChild(savesMenuContainer);
}
createSavesMenu();
}
function startGame() {
gameState = 'playing';
// Hide all menus
mainMenuContainer.alpha = 0;
if (settingsMenuContainer) settingsMenuContainer.alpha = 0;
// Check if player name exists, if not ask for it
var currentPlayerName = storage.currentPlayerName;
if (!currentPlayerName) {
// Show name input dialog
showPlayerNameInput();
return;
}
// Add current player to the list if not already there
addPlayerToList(currentPlayerName);
// Show game with animation
tween(gameContainer, {
alpha: 1
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
// Initialize the game after animation
initializeGrid();
removeInitialMatches();
// Give starting gold for new market experience
gold = 1000;
storage.gold = gold;
// Increment games played counter
if (!storage.gamesPlayed) {
storage.gamesPlayed = 0;
}
storage.gamesPlayed++;
updateUI();
LK.playMusic('7week3days');
}
});
}
// Start with main menu visible
showMainMenu();
;
// Track current cascade combo text to prevent overlapping
var currentCascadeText = null;
function showCascadeComboDisplay(comboLevel) {
if (comboLevel < 1 || comboLevel > 7) return;
var comboName = cascadeComboNames[comboLevel];
if (!comboName) return;
// Remove previous cascade text immediately if it exists
if (currentCascadeText && currentCascadeText.parent) {
tween.stop(currentCascadeText);
currentCascadeText.parent.removeChild(currentCascadeText);
currentCascadeText = null;
}
// Create cascade combo text
var cascadeText = new Text2(comboName, {
size: 100 + comboLevel * 20,
// Size increases with combo level
fill: comboLevel <= 2 ? '#FFFF00' : comboLevel <= 4 ? '#FF8C00' : comboLevel <= 6 ? '#FF0000' : '#FFD700' // Colors get more intense
});
cascadeText.anchor.set(0.5, 0.5);
cascadeText.x = 1024;
cascadeText.y = 1000; // Position below center
cascadeText.alpha = 0;
cascadeText.scaleX = 0.3;
cascadeText.scaleY = 0.3;
game.addChild(cascadeText);
// Set as current cascade text
currentCascadeText = cascadeText;
// Animate cascade text with increasing intensity
var animationDuration = Math.max(800 - comboLevel * 50, 300); // Faster for higher combos
tween(cascadeText, {
alpha: 1,
scaleX: 1.0 + comboLevel * 0.2,
scaleY: 1.0 + comboLevel * 0.2,
rotation: comboLevel % 2 === 0 ? 0.1 : -0.1 // Alternate rotation
}, {
duration: animationDuration,
easing: tween.bounceOut,
onFinish: function onFinish() {
// Hold briefly then fade out
LK.setTimeout(function () {
tween(cascadeText, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 400,
easing: tween.easeIn,
onFinish: function onFinish() {
if (cascadeText.parent) {
cascadeText.parent.removeChild(cascadeText);
}
// Clear reference if this is still the current text
if (currentCascadeText === cascadeText) {
currentCascadeText = null;
}
}
});
}, 1000 + comboLevel * 200); // Hold longer for higher combos
}
});
// Add screen flash effect for higher combos
if (comboLevel >= 3) {
var flashColor = comboLevel <= 4 ? 0xFF8C00 : comboLevel <= 6 ? 0xFF0000 : 0xFFD700;
var flashDuration = Math.min(200 + comboLevel * 100, 800);
LK.effects.flashScreen(flashColor, flashDuration);
}
// Play sound effect
LK.getSound('powerup').play();
}
function createSupernovaReward() {
// Find a random empty position or replace a regular candy
var availablePositions = [];
for (var row = 0; row < GRID_SIZE; row++) {
for (var col = 0; col < GRID_SIZE; col++) {
if (!grid[row][col] || !grid[row][col].isSpecial && Math.random() < 0.3) {
availablePositions.push({
row: row,
col: col
});
}
}
}
if (availablePositions.length > 0) {
var randomPos = availablePositions[Math.floor(Math.random() * availablePositions.length)];
var row = randomPos.row;
var col = randomPos.col;
// Remove existing candy if present
if (grid[row][col] && grid[row][col].parent) {
grid[row][col].parent.removeChild(grid[row][col]);
}
// Create supernova reward
var rewardColor = COLORS[Math.floor(Math.random() * COLORS.length)];
var supernovaReward = new Candy(rewardColor, row, col);
supernovaReward.x = GRID_START_X + col * CELL_SIZE + CELL_SIZE / 2;
supernovaReward.y = GRID_START_Y + row * CELL_SIZE + CELL_SIZE / 2;
supernovaReward.makeSpecial('supernova');
grid[row][col] = supernovaReward;
game.addChild(supernovaReward);
// Add spectacular creation effect for the reward
tween(supernovaReward.graphics, {
scaleX: 2.0,
scaleY: 2.0,
tint: 0xFFD700,
rotation: Math.PI * 4
}, {
duration: 1500,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Add continuous pulsing glow effect
var _pulseSuperNova = function pulseSuperNova() {
if (supernovaReward && supernovaReward.isSpecial && supernovaReward.specialType === 'supernova' && supernovaReward.parent) {
tween(supernovaReward.graphics, {
scaleX: 1.5,
scaleY: 1.5,
tint: 0xFFFF00
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(supernovaReward.graphics, {
scaleX: 1.3,
scaleY: 1.3,
tint: 0xFFFFFF
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
LK.setTimeout(_pulseSuperNova, 200);
}
});
}
});
}
};
_pulseSuperNova();
}
});
// Add massive bonus for 7th cascade combo
score += 50000;
gold += 25000;
updateUI();
// Show special reward text
var rewardText = new Text2('SUPERNOVA REWARD!', {
size: 140,
fill: '#FFD700'
});
rewardText.anchor.set(0.5, 0.5);
rewardText.x = 1024;
rewardText.y = 800;
rewardText.alpha = 0;
rewardText.scaleX = 0.2;
rewardText.scaleY = 0.2;
game.addChild(rewardText);
tween(rewardText, {
alpha: 1,
scaleX: 1.5,
scaleY: 1.5,
rotation: 0.1
}, {
duration: 1000,
easing: tween.bounceOut,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(rewardText, {
alpha: 0,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 500,
easing: tween.easeIn,
onFinish: function onFinish() {
if (rewardText.parent) {
rewardText.parent.removeChild(rewardText);
}
}
});
}, 2000);
}
});
// Create spectacular screen effects
LK.effects.flashScreen(0xFFD700, 1500);
}
}
function showLevelUpNotification(reachedLevel) {
// Create level up notification text
var levelUpText = new Text2('LEVEL ' + reachedLevel + ' REACHED!', {
size: 120,
fill: '#FFD700'
});
levelUpText.anchor.set(0.5, 0.5);
levelUpText.x = 1024;
levelUpText.y = 1366;
levelUpText.alpha = 0;
levelUpText.scaleX = 0.5;
levelUpText.scaleY = 0.5;
game.addChild(levelUpText);
// Animate level text appearing
tween(levelUpText, {
alpha: 1,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 500,
easing: tween.bounceOut,
onFinish: function onFinish() {
// Hold for a moment then fade out
LK.setTimeout(function () {
tween(levelUpText, {
alpha: 0,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {
if (levelUpText.parent) {
levelUpText.parent.removeChild(levelUpText);
}
// Show SUGERCRUSH text after level text disappears
showSugercrushText();
}
});
}, 1500);
}
});
}
function showSugercrushText() {
// Create SUGERCRUSH text
var sugercrushText = new Text2('SUGERCRUSH', {
size: 150,
fill: '#FF6B35'
});
sugercrushText.anchor.set(0.5, 0.5);
sugercrushText.x = 1024;
sugercrushText.y = 1366;
sugercrushText.alpha = 0;
sugercrushText.scaleX = 0.3;
sugercrushText.scaleY = 0.3;
sugercrushText.rotation = -0.2;
game.addChild(sugercrushText);
// Animate SUGERCRUSH text with spectacular effect
tween(sugercrushText, {
alpha: 1,
scaleX: 1.5,
scaleY: 1.5,
rotation: 0.2
}, {
duration: 800,
easing: tween.bounceOut,
onFinish: function onFinish() {
// Add pulsing effect
var pulseCount = 0;
var maxPulses = 3;
var _pulseEffect = function pulseEffect() {
if (pulseCount < maxPulses) {
tween(sugercrushText, {
scaleX: 1.8,
scaleY: 1.8,
tint: 0xFFD700
}, {
duration: 200,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(sugercrushText, {
scaleX: 1.5,
scaleY: 1.5,
tint: 0xFFFFFF
}, {
duration: 200,
easing: tween.easeInOut,
onFinish: function onFinish() {
pulseCount++;
LK.setTimeout(_pulseEffect, 100);
}
});
}
});
} else {
// Final fade out
LK.setTimeout(function () {
tween(sugercrushText, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5,
rotation: 0.5
}, {
duration: 500,
easing: tween.easeIn,
onFinish: function onFinish() {
if (sugercrushText.parent) {
sugercrushText.parent.removeChild(sugercrushText);
}
}
});
}, 1000);
}
};
_pulseEffect();
}
});
// Add screen flash effect
LK.effects.flashScreen(0xFF6B35, 300);
}
function checkSmallCollectorAchievement() {
// Check if all balls have been clicked to small size
if (!achievements.smallCollector && ballsClickedSmall.length >= totalBallsToClick && totalBallsToClick > 0) {
// Achievement unlocked!
achievements.smallCollector = true;
// Save achievement to storage
storage.smallCollectorAchieved = true;
// Award +5000 gold
gold += 5000;
storage.gold = gold;
updateUI();
// Show achievement notification
showAchievementNotification('SMALL COLLECTOR', 'All balls clicked small!', '+5000 Gold');
// Play achievement sound
LK.getSound('powerup').play();
}
}
function checkHiddenStarsAchievement() {
// Check if the sequence 1, 1, 1, 3 has been entered after clicking shooting star
if (!achievements.hiddenStars && hiddenStarsActivated && hiddenStarsSequence.length >= 4) {
if (hiddenStarsSequence[0] === 1 && hiddenStarsSequence[1] === 1 && hiddenStarsSequence[2] === 1 && hiddenStarsSequence[3] === 3) {
// Achievement unlocked!
achievements.hiddenStars = true;
// Save achievement to storage
storage.hiddenStarsAchieved = true;
// Award +8000 gold
gold += 8000;
// Ensure gold is saved to storage
storage.gold = gold;
updateUI();
// Show achievement notification
showAchievementNotification('HIDDEN STARS', 'Secret sequence discovered!', '+8000 Gold');
// Play achievement sound
LK.getSound('powerup').play();
// Reset the tracking variables
hiddenStarsActivated = false;
hiddenStarsSequence = [];
}
}
}
function checkLeaguesAchievement() {
// Check if player has reached level 4
if (!achievements.leagues && level >= 4) {
// Achievement unlocked!
achievements.leagues = true;
// Save achievement to storage
storage.leaguesAchieved = true;
// Add special rewards to map: 1 supernova, 1 Karadeniz, 2 writerpir
var rewardsAdded = 0;
var maxRewards = 4;
// Find positions to place rewards
for (var row = 0; row < GRID_SIZE && rewardsAdded < maxRewards; row++) {
for (var col = 0; col < GRID_SIZE && rewardsAdded < maxRewards; col++) {
if (grid[row][col] && !grid[row][col].isSpecial && Math.random() < 0.3) {
var rewardType;
if (rewardsAdded === 0) {
rewardType = 'supernova'; // 1 supernova
} else if (rewardsAdded === 1) {
rewardType = 'expires'; // 1 Karadeniz (using expires asset)
} else {
rewardType = 'writerpir'; // 2 writerpir
}
// Transform existing candy into reward
grid[row][col].makeSpecial(rewardType);
// Add creation sparkle effect
tween(grid[row][col].graphics, {
scaleX: 1.3,
scaleY: 1.3,
tint: 0xFFD700
}, {
duration: 500,
easing: tween.bounceOut
});
rewardsAdded++;
}
}
}
updateUI();
// Show achievement notification
showAchievementNotification('LEAGUES', 'Reached Level 4!', 'Special rewards added to map!');
// Play achievement sound
LK.getSound('powerup').play();
}
}
function checkUniverseAchievement() {
// Check if a Karadeniz (expires) has been produced
if (!achievements.universe) {
// Achievement unlocked!
achievements.universe = true;
// Save achievement to storage
storage.universeAchieved = true;
// Award +2000 gold
gold += 2000;
storage.gold = gold;
updateUI();
// Show achievement notification
showAchievementNotification('UNIVERSE', 'Karadeniz produced!', '+2000 Gold');
// Play achievement sound
LK.getSound('powerup').play();
}
}
function checkTimelessKaradenizCombinations(allMatches) {
// First check for timeless Karadeniz + timeless Karadeniz combinations
for (var m = 0; m < allMatches.length; m++) {
var matches = allMatches[m];
// Count timeless Karadeniz in this match
var timelessCount = 0;
var timelessCandies = [];
for (var i = 0; i < matches.length; i++) {
var candy = matches[i];
if (candy && candy.isTimeless && candy.specialType === 'expires') {
timelessCount++;
timelessCandies.push(candy);
}
}
// If we have 2 or more timeless Karadeniz in the same match, create warlek
if (timelessCount >= 2) {
// Create warlek effect - turn all candies purple
var firstTimeless = timelessCandies[0];
var secondTimeless = timelessCandies[1];
// Remove both timeless Karadeniz from tracking
for (var t = timelessKaradenizCandies.length - 1; t >= 0; t--) {
if (timelessKaradenizCandies[t] === firstTimeless || timelessKaradenizCandies[t] === secondTimeless) {
timelessKaradenizCandies.splice(t, 1);
}
}
// Create warlek at first timeless position
firstTimeless.makeSpecial('ultraSupernova');
firstTimeless.isTimeless = false;
firstTimeless.specialType = 'warlek';
firstTimeless.isSpecial = true;
// Remove second timeless
grid[secondTimeless.row][secondTimeless.col] = null;
secondTimeless.explode();
// Create spectacular warlek creation effect
tween(firstTimeless.graphics, {
scaleX: 3.0,
scaleY: 3.0,
tint: 0x9013fe,
rotation: Math.PI * 8
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Turn all candies purple with wave effect
turnAllCandiesPurple(firstTimeless);
}
});
// Show warlek creation notification
var warlekText = new Text2('WARLEK CREATED!', {
size: 120,
fill: '#9013fe'
});
warlekText.anchor.set(0.5, 0.5);
warlekText.x = 1024;
warlekText.y = 1366;
warlekText.alpha = 0;
game.addChild(warlekText);
tween(warlekText, {
alpha: 1,
scaleX: 1.5,
scaleY: 1.5,
rotation: 0.2
}, {
duration: 1000,
easing: tween.bounceOut,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(warlekText, {
alpha: 0,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 500,
onFinish: function onFinish() {
if (warlekText.parent) {
warlekText.parent.removeChild(warlekText);
}
}
});
}, 2000);
}
});
// Add massive bonus for warlek creation
score += 50000;
gold += 25000;
updateUI();
LK.effects.flashScreen(0x9013fe, 1500);
LK.getSound('powerup').play();
// Clear the match to prevent further processing
matches.length = 0;
return; // Exit early since warlek was created
}
}
// Check each match group for timeless Karadeniz participation
for (var m = 0; m < allMatches.length; m++) {
var matches = allMatches[m];
// Look for timeless Karadeniz in this match
for (var i = 0; i < matches.length; i++) {
var candy = matches[i];
if (candy && candy.isTimeless && candy.specialType === 'expires') {
// Found timeless Karadeniz in match - it can combine with any candy type
var combiningCandiesCount = matches.length - 1; // Exclude the timeless Karadeniz itself
candy.timelessHealth -= combiningCandiesCount;
// Update cracking effect based on new health
startCrackingEffect(candy);
// Show health status
showTimelessHealthStatus(candy);
// Explode only the combining candies, not the timeless Karadeniz
for (var j = 0; j < matches.length; j++) {
if (matches[j] !== candy) {
// This is a combining candy - explode it with score
explodeCandyWithScore(matches[j]);
grid[matches[j].row][matches[j].col] = null;
}
}
// Check if timeless Karadeniz should explode (when health reaches 0, meaning 40 candies combined)
if (candy.timelessHealth <= 0) {
// Store position for potential recreation
var timelessRow = candy.row;
var timelessCol = candy.col;
// Remove from timeless tracking array
for (var t = 0; t < timelessKaradenizCandies.length; t++) {
if (timelessKaradenizCandies[t] === candy) {
timelessKaradenizCandies.splice(t, 1);
break;
}
}
// Explode the timeless Karadeniz and entire map
explodeEntireMap(candy);
// Schedule check for new combo formation after explosion effects complete
LK.setTimeout(function () {
// Check if new combos formed at the same position after explosion
var newMatches = checkMatch(timelessRow, timelessCol);
if (newMatches.length >= 3) {
// New combo formed - recreate timeless Karadeniz
recreateTimelessKaradeniz(timelessRow, timelessCol);
}
}, 1000); // Wait for explosion effects to complete
return; // Exit early since map exploded
}
// Remove ALL candies from this match since they've been processed
// This prevents them from being processed again in the normal match logic
matches.length = 0;
break; // Only one timeless Karadeniz per match
}
}
}
// Also check for adjacent combinations with timeless Karadeniz
checkTimelessAdjacentCombinations();
}
function checkTimelessAdjacentCombinations() {
// Check if any timeless Karadeniz has adjacent candies it can combine with
for (var t = 0; t < timelessKaradenizCandies.length; t++) {
var timelessCandy = timelessKaradenizCandies[t];
if (!timelessCandy || !timelessCandy.parent) continue;
var row = timelessCandy.row;
var col = timelessCandy.col;
var adjacentPositions = [[-1, 0], [1, 0], [0, -1], [0, 1]];
// Check each adjacent position for any candy to combine with
for (var a = 0; a < adjacentPositions.length; a++) {
var adjRow = row + adjacentPositions[a][0];
var adjCol = col + adjacentPositions[a][1];
if (adjRow >= 0 && adjRow < GRID_SIZE && adjCol >= 0 && adjCol < GRID_SIZE) {
var adjacentCandy = grid[adjRow][adjCol];
// Timeless Karadeniz can combine with any candy type
if (adjacentCandy && adjacentCandy !== timelessCandy && !adjacentCandy.isTimeless) {
// Timeless Karadeniz combines with this adjacent candy directly
timelessCandy.timelessHealth -= 1; // Reduce health by 1 for each candy it combines with
// Update cracking effect
startCrackingEffect(timelessCandy);
// Show health status
showTimelessHealthStatus(timelessCandy);
// Remove the adjacent candy (it gets "consumed" by timeless Karadeniz)
explodeCandyWithScore(adjacentCandy);
grid[adjRow][adjCol] = null;
// Check if timeless Karadeniz should explode (reached 40 combinations)
if (timelessCandy.timelessHealth <= 0) {
// Remove from tracking array
for (var tr = 0; tr < timelessKaradenizCandies.length; tr++) {
if (timelessKaradenizCandies[tr] === timelessCandy) {
timelessKaradenizCandies.splice(tr, 1);
break;
}
}
// Explode entire map
explodeEntireMap(timelessCandy);
return;
}
break; // Only process one adjacent candy per timeless candy per cycle
}
}
}
}
}
function showTimelessHealthStatus(candy) {
if (!candy || !candy.isTimeless) return;
// Calculate remaining combinations needed (health represents remaining combinations)
var remainingCombinations = candy.timelessHealth;
var totalCombinations = 40;
var completedCombinations = totalCombinations - remainingCombinations;
// Create status text showing combinations progress
var statusText = new Text2(completedCombinations + '/' + totalCombinations, {
size: 60,
fill: remainingCombinations > 20 ? '#FFD700' : remainingCombinations > 10 ? '#FF8C00' : '#FF0000'
});
statusText.anchor.set(0.5, 0.5);
statusText.x = candy.x;
statusText.y = candy.y - 120;
statusText.alpha = 0;
game.addChild(statusText);
// Animate status text
tween(statusText, {
alpha: 1,
scaleX: 1.5,
scaleY: 1.5,
y: candy.y - 150
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(statusText, {
alpha: 0,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 300,
onFinish: function onFinish() {
if (statusText.parent) {
statusText.parent.removeChild(statusText);
}
}
});
}, 1000);
}
});
}
function explodeEntireMap(timelessCandy) {
// Transform timeless Karadeniz into red rocket instead of exploding
if (timelessCandy && timelessCandy.parent) {
// Remove timeless properties
timelessCandy.isTimeless = false;
timelessCandy.timelessHealth = 0;
// Transform into red rocket
timelessCandy.makeSpecial('redRocket');
timelessCandy.justCreated = true; // Prevent immediate activation
// Create transformation effect
tween(timelessCandy.graphics, {
scaleX: 1.5,
scaleY: 1.5,
tint: 0x991b1b,
rotation: Math.PI * 2
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
// Reset creation flag after animation
LK.setTimeout(function () {
if (timelessCandy && timelessCandy.parent) {
timelessCandy.justCreated = false;
}
}, 500);
}
});
// Add score bonus for transformation
score += 15000;
gold += 7500;
updateUI();
// Create transformation effects
LK.effects.flashScreen(0x991b1b, 1000);
// Show transformation notification
var transformText = new Text2('TIMELESS KARADENIZ → RED ROCKET!', {
size: 100,
fill: '#991b1b'
});
transformText.anchor.set(0.5, 0.5);
transformText.x = 1024;
transformText.y = 1366;
transformText.alpha = 0;
transformText.scaleX = 0.5;
transformText.scaleY = 0.5;
game.addChild(transformText);
tween(transformText, {
alpha: 1,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 800,
easing: tween.bounceOut,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(transformText, {
alpha: 0,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 500,
onFinish: function onFinish() {
if (transformText.parent) {
transformText.parent.removeChild(transformText);
}
}
});
}, 2000);
}
});
}
}
function startCrackingEffect(candy) {
if (!candy || !candy.isTimeless || !candy.parent) return;
// Calculate crack intensity based on combination progress (40 total combinations needed)
var totalCombinations = 40;
var completedCombinations = totalCombinations - candy.timelessHealth;
var crackIntensity = completedCombinations / totalCombinations; // More cracks as more combinations completed
// Create cracking visual effect with scale pulsing
var pulseScale = 1.0 + crackIntensity * 0.5; // More intense pulsing as more combinations completed
var pulseSpeed = Math.max(2000 - crackIntensity * 1500, 300); // Faster pulsing as more combinations completed
// Apply cracking tint - gets redder as more combinations completed
var crackTint = 0xFF4500; // Orange base
if (crackIntensity > 0.75) {
crackTint = 0xFF0000; // Red when close to explosion (30+ combinations)
} else if (crackIntensity > 0.5) {
crackTint = 0xFF2500; // Dark orange when moderately damaged (20+ combinations)
} else if (crackIntensity > 0.25) {
crackTint = 0xFF3500; // Light orange when lightly damaged (10+ combinations)
}
tween(candy.graphics, {
scaleX: pulseScale,
scaleY: pulseScale,
tint: crackTint,
alpha: 0.8 + crackIntensity * 0.2
}, {
duration: pulseSpeed / 2,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (candy && candy.isTimeless && candy.parent) {
tween(candy.graphics, {
scaleX: 0.8,
scaleY: 0.8,
alpha: 1.0
}, {
duration: pulseSpeed / 2,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Continue cracking effect if still timeless and alive
if (candy && candy.isTimeless && candy.parent && candy.timelessHealth > 0) {
LK.setTimeout(function () {
startCrackingEffect(candy);
}, 100);
}
}
});
}
}
});
}
function showAchievementNotification(title, description, reward) {
// Create achievement notification background
var achievementBg = LK.getAsset('progressBarBg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.0,
scaleY: 3.0
});
achievementBg.x = 1024;
achievementBg.y = 1366;
achievementBg.alpha = 0;
game.addChild(achievementBg);
// Create achievement title text
var titleText = new Text2(title, {
size: 80,
fill: '#FFD700'
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 1266;
titleText.alpha = 0;
game.addChild(titleText);
// Create achievement description text
var descText = new Text2(description, {
size: 60,
fill: '#FFFFFF'
});
descText.anchor.set(0.5, 0.5);
descText.x = 1024;
descText.y = 1366;
descText.alpha = 0;
game.addChild(descText);
// Create achievement reward text
var rewardText = new Text2(reward, {
size: 70,
fill: '#00FF00'
});
rewardText.anchor.set(0.5, 0.5);
rewardText.x = 1024;
rewardText.y = 1466;
rewardText.alpha = 0;
game.addChild(rewardText);
// Animate achievement notification appearing
tween(achievementBg, {
alpha: 0.9,
scaleX: 2.2,
scaleY: 3.2
}, {
duration: 300,
easing: tween.bounceOut
});
tween(titleText, {
alpha: 1,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 400,
easing: tween.bounceOut
});
tween(descText, {
alpha: 1
}, {
duration: 500,
easing: tween.easeOut
});
tween(rewardText, {
alpha: 1,
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 600,
easing: tween.bounceOut,
onFinish: function onFinish() {
// Hold for a moment then fade out
LK.setTimeout(function () {
// Fade out all elements
tween(achievementBg, {
alpha: 0,
scaleX: 1.8,
scaleY: 2.8
}, {
duration: 500,
easing: tween.easeIn
});
tween(titleText, {
alpha: 0,
scaleY: 0.8
}, {
duration: 500,
easing: tween.easeIn
});
tween(descText, {
alpha: 0
}, {
duration: 500,
easing: tween.easeIn
});
tween(rewardText, {
alpha: 0,
scaleY: 0.8
}, {
duration: 500,
easing: tween.easeIn,
onFinish: function onFinish() {
// Clean up elements
if (achievementBg.parent) achievementBg.parent.removeChild(achievementBg);
if (titleText.parent) titleText.parent.removeChild(titleText);
if (descText.parent) descText.parent.removeChild(descText);
if (rewardText.parent) rewardText.parent.removeChild(rewardText);
}
});
}, 3000);
}
});
// Add screen flash effect
LK.effects.flashScreen(0xFFD700, 500);
}
;
function recreateTimelessKaradeniz(row, col) {
// Check if position is valid and has a candy
if (row >= 0 && row < GRID_SIZE && col >= 0 && col < GRID_SIZE && grid[row] && grid[row][col]) {
var candy = grid[row][col];
// Transform candy into timeless Karadeniz
candy.makeSpecial('expires');
candy.isTimeless = true;
candy.timelessHealth = 40; // Reset with full health
candy.maxTimelessHealth = 40;
// Add to timeless tracking array
timelessKaradenizCandies.push(candy);
// Create recreation effect
tween(candy.graphics, {
scaleX: 1.8,
scaleY: 1.8,
tint: 0xFF4500,
rotation: Math.PI * 3
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
// Start cracking effect animation
startCrackingEffect(candy);
}
});
// Show recreation notification
var recreationText = new Text2('TIMELESS KARADENIZ REBORN!', {
size: 80,
fill: '#FF4500'
});
recreationText.anchor.set(0.5, 0.5);
recreationText.x = 1024;
recreationText.y = 1200;
recreationText.alpha = 0;
game.addChild(recreationText);
tween(recreationText, {
alpha: 1,
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 600,
easing: tween.bounceOut,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(recreationText, {
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
if (recreationText.parent) {
recreationText.parent.removeChild(recreationText);
}
}
});
}, 2000);
}
});
// Add bonus for recreation
score += 5000;
gold += 2500;
updateUI();
LK.getSound('powerup').play();
LK.effects.flashScreen(0xFF4500, 800);
}
}
function startLevel7Victory() {
// Stop all processing
isProcessing = true;
// Disable all game controls permanently
gameState = 'victory';
// Hide combo text during victory sequence
tween(comboText, {
alpha: 0
}, {
duration: 300,
easing: tween.easeOut
});
// Stop music
LK.stopMusic();
// Start peaceful music
LK.playMusic('7week3days', {
fade: {
start: 0,
end: 0.3,
duration: 2000
}
});
// Make 99% of stars start sliding
makeStarsSlide();
// Start exploding all 8x8 candies during camera movement
explodeAllCandiesDuringVictory();
// Animate candy table moving up towards sky
tween(gameContainer, {
y: -2000,
// Move game container up and out of view
alpha: 0.8
}, {
duration: 4000,
easing: tween.easeOut,
onFinish: function onFinish() {
// Hide game container completely
gameContainer.alpha = 0;
// Show "KAZANDINIZ" text after table disappears
showVictoryText();
}
});
// Create sky background effect
createSkyBackground();
}
function createSkyBackground() {
// Change game background to sky color
game.setBackgroundColor(0x87CEEB); // Sky blue
}
function showVictoryText() {
// Create "KAZANDINIZ" text
var victoryText = new Text2('KAZANDINIZ', {
size: 200,
fill: '#FFD700'
});
victoryText.anchor.set(0.5, 0.5);
victoryText.x = 1024;
victoryText.y = 1366;
victoryText.alpha = 0;
victoryText.scaleX = 0.3;
victoryText.scaleY = 0.3;
game.addChild(victoryText);
// Animate victory text appearing
tween(victoryText, {
alpha: 1,
scaleX: 1.5,
scaleY: 1.5,
rotation: 0.1
}, {
duration: 1500,
easing: tween.bounceOut,
onFinish: function onFinish() {
// Wait 2 seconds then show congratulations
LK.setTimeout(function () {
showCongratulationsText(victoryText);
}, 2000);
}
});
}
function showCongratulationsText(victoryText) {
// Fade out victory text
tween(victoryText, {
alpha: 0,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 800,
easing: tween.easeIn,
onFinish: function onFinish() {
if (victoryText.parent) victoryText.parent.removeChild(victoryText);
}
});
// Create "Gerçekten tebrik ederim" text
var congratsText = new Text2('Gerçekten tebrik ederim', {
size: 120,
fill: '#FFFFFF'
});
congratsText.anchor.set(0.5, 0.5);
congratsText.x = 1024;
congratsText.y = 1366;
congratsText.alpha = 0;
game.addChild(congratsText);
// Animate congratulations text
tween(congratsText, {
alpha: 1,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
// Wait then show credits
LK.setTimeout(function () {
showCreditsSequence(congratsText);
}, 2000);
}
});
}
function showCreditsSequence(congratsText) {
// Fade out congratulations text
tween(congratsText, {
alpha: 0,
y: congratsText.y - 200
}, {
duration: 800,
easing: tween.easeIn,
onFinish: function onFinish() {
if (congratsText.parent) congratsText.parent.removeChild(congratsText);
}
});
// Create credits text "yapımcılar TIKLA SUNUCUSU"
var creditsText = new Text2('yapımcılar TIKLA SUNUCUSU', {
size: 80,
fill: '#FFD700'
});
creditsText.anchor.set(0.5, 0.5);
creditsText.x = 1024;
creditsText.y = 2800; // Start from bottom
creditsText.alpha = 1;
game.addChild(creditsText);
// Animate credits scrolling slowly upward
tween(creditsText, {
y: -200 // Move to top and beyond
}, {
duration: 8000,
easing: tween.linear,
onFinish: function onFinish() {
if (creditsText.parent) creditsText.parent.removeChild(creditsText);
// Show thank you message
showThankYouMessage();
}
});
}
function showThankYouMessage() {
// Create "oynadığınız için teşekkürler" text
var thankYouText = new Text2('oynadığınız için teşekkürler', {
size: 100,
fill: '#FFFFFF'
});
thankYouText.anchor.set(0.5, 0.5);
thankYouText.x = 1024;
thankYouText.y = 1366;
thankYouText.alpha = 0;
game.addChild(thankYouText);
// Animate thank you text
tween(thankYouText, {
alpha: 1,
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 1200,
easing: tween.easeOut,
onFinish: function onFinish() {
// Wait then create supernova from sky
LK.setTimeout(function () {
createSkySupernova(thankYouText);
}, 3000);
}
});
}
function createSkySupernova(thankYouText) {
// Create supernova in the sky
var skySupernova = LK.getAsset('supernova', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.1,
scaleY: 0.1,
x: 1024,
y: 400,
// Top part of sky
alpha: 0
});
game.addChild(skySupernova);
// Animate supernova explosion
tween(skySupernova, {
alpha: 1,
scaleX: 8.0,
scaleY: 8.0,
tint: 0xFFFFFF,
rotation: Math.PI * 8
}, {
duration: 3000,
easing: tween.easeOut,
onFinish: function onFinish() {
// Create massive screen flash
LK.effects.flashScreen(0xFFFFFF, 2000);
// Win the game
LK.setTimeout(function () {
LK.showYouWin();
}, 1000);
}
});
// Fade out thank you text during supernova
tween(thankYouText, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 2000,
easing: tween.easeIn,
onFinish: function onFinish() {
if (thankYouText.parent) thankYouText.parent.removeChild(thankYouText);
}
});
}
function turnAllCandiesPurple(warlekCandy) {
// Turn all candies on the grid purple with expanding wave effect
var centerRow = warlekCandy.row;
var centerCol = warlekCandy.col;
var maxDistance = Math.max(GRID_SIZE, GRID_SIZE);
for (var distance = 1; distance <= maxDistance; distance++) {
(function (dist) {
LK.setTimeout(function () {
// Collect all candies at this distance
var candiesAtDistance = [];
for (var r = 0; r < GRID_SIZE; r++) {
for (var c = 0; c < GRID_SIZE; c++) {
var actualDist = Math.max(Math.abs(r - centerRow), Math.abs(c - centerCol));
if (actualDist === dist && grid[r][c] && grid[r][c] !== warlekCandy) {
candiesAtDistance.push(grid[r][c]);
}
}
}
// Transform all candies at this distance to purple
for (var i = 0; i < candiesAtDistance.length; i++) {
(function (targetCandy, index) {
if (targetCandy && targetCandy.parent) {
// Update candy type to purple
targetCandy.type = 'purple';
// Remove old graphics
targetCandy.removeChild(targetCandy.graphics);
// Create new purple graphics
targetCandy.graphics = targetCandy.attachAsset('purpleCandy', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
});
// Reset special properties
targetCandy.isSpecial = false;
targetCandy.specialType = null;
targetCandy.isTimeless = false;
// Add transformation effect
tween(targetCandy.graphics, {
scaleX: 1.3,
scaleY: 1.3,
tint: 0x9013fe
}, {
duration: 400,
easing: tween.bounceOut,
onFinish: function onFinish() {
tween(targetCandy.graphics, {
scaleX: 0.8,
scaleY: 0.8,
tint: 0xFFFFFF
}, {
duration: 300,
easing: tween.easeOut
});
}
});
}
})(candiesAtDistance[i], i);
}
}, dist * 150); // Stagger waves outward
})(distance);
}
}
function makeStarsSlide() {
// Make 99% of all stars start sliding continuously
if (starField && starField.children) {
for (var i = 0; i < starField.children.length; i++) {
var star = starField.children[i];
// 99% chance for each star to start sliding
if (Math.random() < 0.99) {
// Set sliding properties for continuous sliding
star.slideSpeed = Math.random() * 3 + 1; // Random slide speed
star.slideDirection = Math.random() * Math.PI * 2; // Random direction
star.isSliding = true; // Flag to indicate continuous sliding
// Start continuous sliding animation
var _slideStarContinuously = function slideStarContinuously(starToSlide) {
if (starToSlide && starToSlide.parent && starToSlide.isSliding && gameState === 'victory') {
// Move star in its sliding direction
starToSlide.x += Math.cos(starToSlide.slideDirection) * starToSlide.slideSpeed;
starToSlide.y += Math.sin(starToSlide.slideDirection) * starToSlide.slideSpeed;
// Wrap around screen edges
if (starToSlide.x < -50) starToSlide.x = 2098;
if (starToSlide.x > 2098) starToSlide.x = -50;
if (starToSlide.y < -50) starToSlide.y = 2782;
if (starToSlide.y > 2782) starToSlide.y = -50;
// Continue sliding
LK.setTimeout(function () {
_slideStarContinuously(starToSlide);
}, 16); // ~60fps sliding
}
};
_slideStarContinuously(star);
}
}
}
}
function explodeAllCandiesDuringVictory() {
// Create spectacular explosion effects for all candies in the 8x8 grid
var allCandies = [];
// Collect all candies from the 8x8 grid
for (var row = 0; row < GRID_SIZE; row++) {
for (var col = 0; col < GRID_SIZE; col++) {
if (grid[row][col] && grid[row][col].parent) {
// Calculate distance from center for wave explosion effect
var centerRow = GRID_SIZE / 2;
var centerCol = GRID_SIZE / 2;
var distance = Math.sqrt(Math.pow(row - centerRow, 2) + Math.pow(col - centerCol, 2));
allCandies.push({
candy: grid[row][col],
distance: distance,
row: row,
col: col
});
}
}
}
// Sort candies by distance from center for wave explosion effect
allCandies.sort(function (a, b) {
return a.distance - b.distance;
});
// Create expanding explosion waves from center outward
for (var i = 0; i < allCandies.length; i++) {
(function (candyData, index) {
var delay = candyData.distance * 150 + index * 20; // Stagger explosions based on distance and index
LK.setTimeout(function () {
var candy = candyData.candy;
if (candy && candy.parent) {
// Create spectacular explosion effect for each candy
tween(candy.graphics, {
scaleX: 2.5,
scaleY: 2.5,
tint: 0xFFD700,
rotation: candy.graphics.rotation + Math.PI * 4,
alpha: 0.8
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
// Final explosion burst
tween(candy, {
scaleX: 4.0,
scaleY: 4.0,
alpha: 0,
rotation: candy.rotation + Math.PI * 6
}, {
duration: 400,
easing: tween.easeIn,
onFinish: function onFinish() {
// Remove candy from grid and game
if (candy.parent) {
candy.parent.removeChild(candy);
}
grid[candyData.row][candyData.col] = null;
}
});
}
});
}
}, delay);
})(allCandies[i], i);
}
// Create massive screen flash effects during the explosion sequence
LK.setTimeout(function () {
LK.effects.flashScreen(0xFFD700, 1000);
}, 500);
LK.setTimeout(function () {
LK.effects.flashScreen(0xFFFFFF, 1200);
}, 1500);
LK.setTimeout(function () {
LK.effects.flashScreen(0xFFD700, 800);
}, 2800);
}
function showPlayerNameInput() {
// Create name input dialog background
var inputBg = LK.getAsset('progressBarBg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 3.0,
scaleY: 4.0
});
inputBg.x = 1024;
inputBg.y = 1366;
game.addChild(inputBg);
// Create title text
var titleText = new Text2('Adınızı Girin:', {
size: 80,
fill: '#FFD700'
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 1200;
game.addChild(titleText);
// Create instruction text
var instructionText = new Text2('Lütfen 3-15 karakter arası bir ad girin', {
size: 50,
fill: '#FFFFFF'
});
instructionText.anchor.set(0.5, 0.5);
instructionText.x = 1024;
instructionText.y = 1300;
game.addChild(instructionText);
// Create sample names for selection
var sampleNames = ['Oyuncu', 'Şeker Avcısı', 'Kombo Ustası', 'Patlat Kralı', 'Candy Master'];
var selectedNameIndex = 0;
var currentName = sampleNames[0];
// Create display text for selected name
var nameDisplayText = new Text2(currentName, {
size: 70,
fill: '#00FF00'
});
nameDisplayText.anchor.set(0.5, 0.5);
nameDisplayText.x = 1024;
nameDisplayText.y = 1400;
game.addChild(nameDisplayText);
// Create navigation buttons
var prevButton = LK.getAsset('progressBarBg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.0,
scaleY: 1.0
});
prevButton.x = 800;
prevButton.y = 1400;
game.addChild(prevButton);
var prevButtonText = new Text2('<', {
size: 60,
fill: '#FFFFFF'
});
prevButtonText.anchor.set(0.5, 0.5);
prevButtonText.x = 800;
prevButtonText.y = 1400;
game.addChild(prevButtonText);
var nextButton = LK.getAsset('progressBarBg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.0,
scaleY: 1.0
});
nextButton.x = 1248;
nextButton.y = 1400;
game.addChild(nextButton);
var nextButtonText = new Text2('>', {
size: 60,
fill: '#FFFFFF'
});
nextButtonText.anchor.set(0.5, 0.5);
nextButtonText.x = 1248;
nextButtonText.y = 1400;
game.addChild(nextButtonText);
// Create confirm button
var confirmButton = LK.getAsset('progressBarBg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.0,
scaleY: 1.5
});
confirmButton.x = 1024;
confirmButton.y = 1550;
game.addChild(confirmButton);
var confirmButtonText = new Text2('ONAYLA', {
size: 60,
fill: '#FFFFFF'
});
confirmButtonText.anchor.set(0.5, 0.5);
confirmButtonText.x = 1024;
confirmButtonText.y = 1550;
game.addChild(confirmButtonText);
// Store references for cleanup
var inputElements = [inputBg, titleText, instructionText, nameDisplayText, prevButton, prevButtonText, nextButton, nextButtonText, confirmButton, confirmButtonText];
// Handle input navigation
function handleNameInputClick(x, y) {
// Check prev button
var dx = x - prevButton.x;
var dy = y - prevButton.y;
if (Math.sqrt(dx * dx + dy * dy) < 100) {
selectedNameIndex = (selectedNameIndex - 1 + sampleNames.length) % sampleNames.length;
currentName = sampleNames[selectedNameIndex];
nameDisplayText.setText(currentName);
return;
}
// Check next button
dx = x - nextButton.x;
dy = y - nextButton.y;
if (Math.sqrt(dx * dx + dy * dy) < 100) {
selectedNameIndex = (selectedNameIndex + 1) % sampleNames.length;
currentName = sampleNames[selectedNameIndex];
nameDisplayText.setText(currentName);
return;
}
// Check confirm button
dx = x - confirmButton.x;
dy = y - confirmButton.y;
if (Math.sqrt(dx * dx + dy * dy) < 150) {
// Validate name
if (currentName.length >= 3 && currentName.length <= 15) {
// Save player name
storage.currentPlayerName = currentName;
// Clean up input elements
for (var i = 0; i < inputElements.length; i++) {
if (inputElements[i].parent) {
inputElements[i].parent.removeChild(inputElements[i]);
}
}
// Remove input handler
game.nameInputHandler = null;
// Start the game
startGame();
} else {
// Show validation error
var errorText = new Text2('Ad 3-15 karakter arası olmalı!', {
size: 50,
fill: '#FF0000'
});
errorText.anchor.set(0.5, 0.5);
errorText.x = 1024;
errorText.y = 1650;
errorText.alpha = 0;
game.addChild(errorText);
tween(errorText, {
alpha: 1
}, {
duration: 300,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(errorText, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
if (errorText.parent) {
errorText.parent.removeChild(errorText);
}
}
});
}, 2000);
}
});
}
return;
}
}
// Set up input handler
game.nameInputHandler = handleNameInputClick;
}
function addPlayerToList(playerName) {
// Get existing player names
var playerNames = storage.playerNames || [];
// Check if player already exists
var exists = false;
for (var i = 0; i < playerNames.length; i++) {
if (playerNames[i] === playerName) {
exists = true;
break;
}
}
// Add player if not exists - this ensures all players are tracked
if (!exists) {
playerNames.push(playerName);
// Increase limit to show more players publicly (last 20 players)
if (playerNames.length > 20) {
playerNames = playerNames.slice(-20);
}
// Store updated player list - this is visible to all players
storage.playerNames = playerNames;
}
} /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
inventory: {},
gold: 0
});
/****
* Classes
****/
var Candy = Container.expand(function (type, row, col) {
var self = Container.call(this);
self.type = type;
self.row = row;
self.col = col;
self.isSpecial = false;
self.specialType = null;
self.matchCount = 0;
var assetMap = {
'blue': 'blueCandy',
'red': 'redCandy',
'green': 'greenCandy',
'orange': 'orangeCandy',
'purple': 'purpleCandy'
};
var specialAssetMap = {
'blueBomb': 'blueBomb',
'redRocket': 'redRocket',
'greenPentagon': 'greenPentagon',
'orangeLollipop': 'orangeLollipop',
'purpleBerry': 'purpleBerry',
'discoBall': 'discoBall',
'blackHole': 'blackHole',
'supernova': 'supernova',
'expires': 'expires',
'writerpir': 'writerpir',
'vriper': 'vriper',
'converter': 'vriper',
'hourglass': 'hourglass',
'eternal': 'purpleCandy',
'void': 'purpleCandy',
'infiniteVoid': 'purpleCandy',
'warlek': 'ultraSupernova'
};
self.graphics = self.attachAsset(assetMap[type], {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
});
self.makeSpecial = function (specialType) {
self.isSpecial = true;
self.specialType = specialType;
// Stop any existing pattern animations by stopping all tweens on graphics
if (self.graphics) {
tween.stop(self.graphics);
}
self.removeChild(self.graphics);
// Safety check to ensure asset exists in specialAssetMap
var assetId = specialAssetMap[specialType];
if (!assetId) {
// Fallback to a default asset if specialType is not found
assetId = 'purpleCandy';
console.warn('Special type not found in specialAssetMap:', specialType, 'using fallback asset');
}
self.graphics = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
});
};
self.explode = function () {
tween(self, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 0
}, {
duration: 200,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (self.parent) {
self.parent.removeChild(self);
}
}
});
};
return self;
});
var ShootingStar = Container.expand(function () {
var self = Container.call(this);
var star = LK.getAsset('gridLine', {
width: 8,
height: 8,
color: 0xFFFFFF,
shape: 'ellipse',
anchorX: 0.5,
anchorY: 0.5
});
self.addChild(star);
// Set random starting position at top of screen
self.x = Math.random() * 2048;
self.y = -50;
// Set falling speed
self.speed = Math.random() * 5 + 3;
// Add trail effect
self.alpha = 0.9;
self.update = function () {
// Only update position if still visible
if (self.y <= 2732 + 100) {
self.y += self.speed;
}
// Remove when off screen (both vertically and horizontally)
if (self.y > 2732 + 50 || self.x < -100 || self.x > 2148) {
if (self.parent) {
self.parent.removeChild(self);
}
}
};
return self;
});
var StarField = Container.expand(function () {
var self = Container.call(this);
var stars = [];
var numStars = 15; // Further reduced for better performance
var twinkleTimer = 0;
self.twinkle = function (star) {
var targetAlpha = Math.random() * 0.6 + 0.3;
var duration = Math.random() * 4000 + 3000; // Even longer duration
tween(star, {
alpha: targetAlpha
}, {
duration: duration,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Add much longer delay before next twinkle to reduce frequency
LK.setTimeout(function () {
if (star && star.parent) {
// Safety check
self.twinkle(star);
}
}, Math.random() * 5000 + 4000); // Much longer delay
}
});
};
// Create individual stars
for (var i = 0; i < numStars; i++) {
var star = LK.getAsset('gridLine', {
width: Math.random() * 6 + 2,
height: Math.random() * 6 + 2,
color: 0xFFFFFF,
shape: 'ellipse',
anchorX: 0.5,
anchorY: 0.5,
x: Math.random() * 2048,
y: Math.random() * 2732,
alpha: Math.random() * 0.8 + 0.2
});
self.addChild(star);
stars.push(star);
// Start twinkling animation for each star with longer staggered timing
LK.setTimeout(function () {
if (star && star.parent) {
// Safety check
self.twinkle(star);
}
}, i * 500 + Math.random() * 2000); // Much longer stagger times with randomization
}
// Track shooting stars
var shootingStars = [];
// Create shooting star occasionally
self.createShootingStar = function () {
var shootingStar = new ShootingStar();
self.addChild(shootingStar);
shootingStars.push(shootingStar);
};
self.update = function () {
// Reduce update frequency to improve performance
if (LK.ticks % 30 !== 0) return; // Only update every 30 frames (0.5 seconds)
// Clean up shooting stars that are off screen
for (var i = shootingStars.length - 1; i >= 0; i--) {
var star = shootingStars[i];
if (star.y > 2732 + 50 || star.x < -100 || star.x > 2148) {
// Remove from parent to prevent memory leaks
if (star.parent) {
star.parent.removeChild(star);
}
shootingStars.splice(i, 1);
}
}
// Reduce shooting star creation frequency to improve performance
if (Math.random() < 0.005 && shootingStars.length < 3) {
// 0.5% chance per frame, max 3 shooting stars
self.createShootingStar();
}
// Simplified sliding movement with performance optimization
for (var i = 0; i < shootingStars.length; i++) {
var star = shootingStars[i];
// Check if this star should slide (reduced to 20% chance)
if (star.shouldSlide === undefined) {
star.shouldSlide = Math.random() < 0.2; // 20% chance
star.slideDirection = Math.random() * Math.PI * 2; // Random direction
star.slideSpeed = Math.random() * 1 + 0.5; // Reduced slide speed
}
// Apply sliding movement if enabled
if (star.shouldSlide) {
star.x += Math.cos(star.slideDirection) * star.slideSpeed;
// Keep star within screen bounds horizontally
if (star.x < -50 || star.x > 2098) {
star.slideDirection = Math.PI - star.slideDirection; // Reverse horizontal direction
}
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2E1065
});
/****
* Game Code
****/
// Define getRequiredScoreForLevel function in global scope
function getRequiredScoreForLevel(targetLevel) {
if (targetLevel <= 1) return 0;
if (targetLevel === 2) return 50000;
// For levels 3+: 50000 * 4^(level-2)
return 50000 * Math.pow(4, targetLevel - 2);
}
var GRID_SIZE = 8;
var CELL_SIZE = 200;
var GRID_START_X = 224;
var GRID_START_Y = 566;
var COLORS = ['blue', 'red', 'green', 'orange', 'purple'];
var grid = [];
var selectedCandy = null;
var score = 0;
var level = 1;
var gold = 0;
// Reset gold to starting value
storage.gold = gold;
var inventory = {};
// Reset inventory to empty
storage.inventory = inventory;
var isProcessing = false;
var comboMultiplier = 1;
// Secret feature variables
var secretMode = false;
var secretBalls = [];
var secretClickSequence = []; // Track sequence of ball clicks
var secretGridBackup = null; // Backup of original grid state
var onlySpecialCandies = false; // Flag to spawn only special candies
var cascadeComboCount = 0; // Track consecutive cascade combos
var savedComboCount = 0; // Track saved combo count from hourglass
var cascadeComboNames = ['', 'COMBO', 'DOUBLE COMBO', 'BRUTALITY', 'AMAZING', 'SUPERBEAST', 'ULTRA SUPER COMBO', 'PERFECT']; // Combo names for each level
var lastCascadeTime = 0; // Track time of last cascade for timeout
var hourglassCount = 0; // Track number of hourglasses available
var yellowCandiesClicked = []; // Track yellow candies that have been clicked small
// Timeless Karadeniz system variables
var timelessKaradenizCandies = []; // Track all timeless Karadeniz candies
var lastClickTime = 0; // Track last click time for double-click detection
var lastClickedCandy = null; // Track last clicked candy for double-click detection
var DOUBLE_CLICK_THRESHOLD = 500; // Maximum time between clicks for double-click (ms)
// Black hole click tracking for void creation
var blackHoleClickCounts = {}; // key: row_col, value: click count
var voidPositions = []; // Array of {row, col} for voids on the grid
var eternalCandies = []; // Array to track eternal candies on the grid
var selectedEternalCandy = null; // Track selected eternal candy for swapping
// Helper: get key for black hole/void click tracking
function getGridKey(row, col) {
return row + "_" + col;
}
// Helper: create an eternal candy of specific type at a given position
function createEternalCandyOfType(row, col, candyType) {
// Remove any candy at this position
if (grid[row][col] && grid[row][col].parent) {
grid[row][col].parent.removeChild(grid[row][col]);
}
// Create eternal candy with the specified type
var eternalCandy = new Candy(candyType, row, col);
eternalCandy.isSpecial = true;
eternalCandy.specialType = 'eternal';
eternalCandy.type = 'eternal' + candyType.charAt(0).toUpperCase() + candyType.slice(1); // e.g., 'eternalBlue'
eternalCandy.baseType = candyType; // Store original type for combo logic
eternalCandy.canSwapAnywhere = true;
// Replace graphics with eternal look based on candy type
eternalCandy.removeChild(eternalCandy.graphics);
var assetMap = {
'blue': 'blueCandy',
'red': 'redCandy',
'green': 'greenCandy',
'orange': 'orangeCandy',
'purple': 'purpleCandy'
};
eternalCandy.graphics = eternalCandy.attachAsset(assetMap[candyType], {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
});
tween(eternalCandy.graphics, {
tint: 0xFFD700,
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 500,
onFinish: function onFinish() {
// Add continuous golden glow effect
var _pulseEternal = function pulseEternal() {
if (eternalCandy && eternalCandy.parent && eternalCandy.specialType === 'eternal') {
tween(eternalCandy.graphics, {
tint: 0xFFFF00,
scaleX: 1.5,
scaleY: 1.5,
alpha: 0.9
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(eternalCandy.graphics, {
tint: 0xFFD700,
scaleX: 1.3,
scaleY: 1.3,
alpha: 1.0
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
LK.setTimeout(_pulseEternal, 200);
}
});
}
});
}
};
_pulseEternal();
}
});
// Add to grid and game
grid[row][col] = eternalCandy;
gameContainer.addChild(eternalCandy);
// Track eternal candy
eternalCandies.push({
row: row,
col: col
});
}
// Helper: create an eternal candy at a given position
function createEternalCandy(row, col) {
// Remove any candy at this position
if (grid[row][col] && grid[row][col].parent) {
grid[row][col].parent.removeChild(grid[row][col]);
}
// Create eternal candy (special candy with unique properties)
var eternalCandy = new Candy('purple', row, col);
eternalCandy.isSpecial = true;
eternalCandy.specialType = 'eternal';
eternalCandy.type = 'eternal';
eternalCandy.canSwapAnywhere = true;
// Replace graphics with a unique eternal look (golden glowing purple)
eternalCandy.removeChild(eternalCandy.graphics);
eternalCandy.graphics = eternalCandy.attachAsset('purpleCandy', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
});
tween(eternalCandy.graphics, {
tint: 0xFFD700,
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 500,
onFinish: function onFinish() {
// Add continuous golden glow effect
var _pulseEternal = function pulseEternal() {
if (eternalCandy && eternalCandy.parent && eternalCandy.specialType === 'eternal') {
tween(eternalCandy.graphics, {
tint: 0xFFFF00,
scaleX: 1.5,
scaleY: 1.5,
alpha: 0.9
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(eternalCandy.graphics, {
tint: 0xFFD700,
scaleX: 1.3,
scaleY: 1.3,
alpha: 1.0
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
LK.setTimeout(_pulseEternal, 200);
}
});
}
});
}
};
_pulseEternal();
}
});
// Add to grid and game
grid[row][col] = eternalCandy;
gameContainer.addChild(eternalCandy);
// Track eternal candy
eternalCandies.push({
row: row,
col: col
});
// Visual effect
LK.effects.flashScreen(0xFFD700, 1000);
// Show notification
var eternalText = new Text2('EBEDI ŞEKER YARATILDI!', {
size: 90,
fill: '#FFD700'
});
eternalText.anchor.set(0.5, 0.5);
eternalText.x = 1024;
eternalText.y = 1366;
eternalText.alpha = 0;
game.addChild(eternalText);
tween(eternalText, {
alpha: 1,
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 500,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(eternalText, {
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
if (eternalText.parent) eternalText.parent.removeChild(eternalText);
}
});
}, 1500);
}
});
}
// Helper: check if a candy is eternal
function isEternalCandy(candy) {
return candy && candy.isSpecial && candy.specialType === 'eternal';
}
// Helper: handle eternal candy swapping with any candy on the map
function handleEternalCandySwap(eternalCandy, targetCandy) {
if (!eternalCandy || !targetCandy || eternalCandy === targetCandy) return false;
var eternalRow = eternalCandy.row;
var eternalCol = eternalCandy.col;
var targetRow = targetCandy.row;
var targetCol = targetCandy.col;
// Swap positions in grid
grid[eternalRow][eternalCol] = targetCandy;
grid[targetRow][targetCol] = eternalCandy;
// Update candy properties
eternalCandy.row = targetRow;
eternalCandy.col = targetCol;
targetCandy.row = eternalRow;
targetCandy.col = eternalCol;
// Animate the swap with spectacular effect
tween(eternalCandy, {
x: GRID_START_X + targetCol * CELL_SIZE + CELL_SIZE / 2,
y: GRID_START_Y + targetRow * CELL_SIZE + CELL_SIZE / 2,
scaleX: 1.5,
scaleY: 1.5,
tint: 0xFFFFFF
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(eternalCandy, {
scaleX: 1.3,
scaleY: 1.3,
tint: 0xFFD700
}, {
duration: 200,
easing: tween.easeOut
});
}
});
tween(targetCandy, {
x: GRID_START_X + eternalCol * CELL_SIZE + CELL_SIZE / 2,
y: GRID_START_Y + eternalRow * CELL_SIZE + CELL_SIZE / 2
}, {
duration: 300,
easing: tween.easeOut
});
// Update eternal candy position tracking
for (var i = 0; i < eternalCandies.length; i++) {
if (eternalCandies[i].row === eternalRow && eternalCandies[i].col === eternalCol) {
eternalCandies[i].row = targetRow;
eternalCandies[i].col = targetCol;
break;
}
}
// Create swap effect
LK.effects.flashScreen(0xFFD700, 500);
return true;
}
// Helper: create a void at a given position
function createVoidAt(row, col) {
// Remove any candy at this position
if (grid[row][col] && grid[row][col].parent) {
grid[row][col].parent.removeChild(grid[row][col]);
}
// Create a void object (special candy with type 'void')
var voidCandy = new Candy('purple', row, col);
voidCandy.isSpecial = true;
voidCandy.specialType = 'void';
voidCandy.type = 'void';
voidCandy.voidComboType = null; // Will be set on first combo
voidCandy.voidComboActive = false;
// Replace graphics with a unique void look (purpleCandy with special tint)
voidCandy.removeChild(voidCandy.graphics);
voidCandy.graphics = voidCandy.attachAsset('purpleCandy', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
});
tween(voidCandy.graphics, {
tint: 0x6e00ff,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 400,
onFinish: function onFinish() {
tween(voidCandy.graphics, {
tint: 0x9013fe,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 300
});
}
});
// Add to grid and game
grid[row][col] = voidCandy;
gameContainer.addChild(voidCandy);
// Track void position
voidPositions.push({
row: row,
col: col
});
}
// Helper: check if a candy is a void
function isVoidCandy(candy) {
return candy && candy.isSpecial && candy.specialType === 'void';
}
// Helper: get all void candies on the grid
function getAllVoidCandies() {
var result = [];
for (var i = 0; i < voidPositions.length; i++) {
var pos = voidPositions[i];
if (grid[pos.row][pos.col] && isVoidCandy(grid[pos.row][pos.col])) {
result.push(grid[pos.row][pos.col]);
}
}
return result;
}
// Helper: clear all voids from the grid and voidPositions
function clearAllVoids() {
for (var i = 0; i < voidPositions.length; i++) {
var pos = voidPositions[i];
if (grid[pos.row][pos.col] && grid[pos.row][pos.col].parent) {
grid[pos.row][pos.col].parent.removeChild(grid[pos.row][pos.col]);
}
grid[pos.row][pos.col] = null;
}
voidPositions = [];
}
// Helper: handle timeless black hole combo logic - NEW FUNCTIONALITY
function handleTimelessBlackHoleCombo(matchArr) {
// Find if any timeless black hole is in this match
var timelessBlackHole = null;
for (var i = 0; i < matchArr.length; i++) {
if (matchArr[i] && matchArr[i].isSpecial && matchArr[i].specialType === 'expires' && matchArr[i].isTimeless) {
timelessBlackHole = matchArr[i];
break;
}
}
if (!timelessBlackHole) return false;
// NEW FUNCTIONALITY PLACEHOLDER - Add your desired behavior here
// For now, just show a message that functionality is being changed
var changeText = new Text2('ZAMANSIZ KARA DELİK İŞLEVİ DEĞİŞTİRİLİYOR...', {
size: 80,
fill: '#FF0000'
});
changeText.anchor.set(0.5, 0.5);
changeText.x = 1024;
changeText.y = 1366;
changeText.alpha = 0;
game.addChild(changeText);
tween(changeText, {
alpha: 1,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 400,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(changeText, {
alpha: 0
}, {
duration: 400,
onFinish: function onFinish() {
if (changeText.parent) changeText.parent.removeChild(changeText);
}
});
}, 1200);
}
});
// Remove the timeless black hole for now
grid[timelessBlackHole.row][timelessBlackHole.col] = null;
timelessBlackHole.explode();
return true;
}
// Helper: handle void combo logic
function handleVoidCombo(matchArr) {
// Find if any void is in this match
var voidCandy = null;
var infiniteVoidCandy = null;
for (var i = 0; i < matchArr.length; i++) {
if (isVoidCandy(matchArr[i])) {
voidCandy = matchArr[i];
// Check if this is an infinite void (enhanced void with special property)
if (matchArr[i].isInfiniteVoid) {
infiniteVoidCandy = matchArr[i];
}
break;
}
}
if (!voidCandy) return false;
// Check for infinite void + purple candy combo first
if (infiniteVoidCandy) {
var purpleCandy = null;
for (var i = 0; i < matchArr.length; i++) {
if (matchArr[i] !== infiniteVoidCandy && matchArr[i].type === 'purple' && !matchArr[i].isSpecial) {
purpleCandy = matchArr[i];
break;
}
}
if (purpleCandy) {
// Create eternal candy at infinite void position
createEternalCandy(infiniteVoidCandy.row, infiniteVoidCandy.col);
// Remove purple candy
grid[purpleCandy.row][purpleCandy.col] = null;
purpleCandy.explode();
// Remove infinite void
grid[infiniteVoidCandy.row][infiniteVoidCandy.col] = null;
infiniteVoidCandy.explode();
return true;
}
}
// Find the type of candy being comboed with void
var comboType = null;
for (var i = 0; i < matchArr.length; i++) {
if (matchArr[i] !== voidCandy && !isVoidCandy(matchArr[i])) {
comboType = matchArr[i].type;
break;
}
}
if (!comboType) return false;
// Transform all candies of comboType on the map to void
for (var row = 0; row < GRID_SIZE; row++) {
for (var col = 0; col < GRID_SIZE; col++) {
var c = grid[row][col];
if (c && c.type === comboType && !isVoidCandy(c)) {
createVoidAt(row, col);
}
}
}
// Trigger 4x4 attraction effect for the original void
LK.setTimeout(function () {
triggerVoid4x4Attraction(voidCandy);
}, 500);
// Visual effect
LK.effects.flashScreen(0x6e00ff, 800);
// Show notification
var voidText = new Text2('VOID CONSUMES ALL ' + comboType.toUpperCase() + '!', {
size: 80,
fill: '#6e00ff'
});
voidText.anchor.set(0.5, 0.5);
voidText.x = 1024;
voidText.y = 1366;
voidText.alpha = 0;
game.addChild(voidText);
tween(voidText, {
alpha: 1,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 400,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(voidText, {
alpha: 0
}, {
duration: 400,
onFinish: function onFinish() {
if (voidText.parent) voidText.parent.removeChild(voidText);
}
});
}, 1200);
}
});
return true;
}
// Helper: trigger eternal candy 6x6 attraction with 80% bonus
function triggerEternal6x6Attraction(eternalCandy) {
if (!eternalCandy || !eternalCandy.parent) return;
var centerRow = eternalCandy.row;
var centerCol = eternalCandy.col;
// Collect all candies in 6x6 area around eternal candy (3 cells in each direction)
var attractedCandies = [];
for (var r = Math.max(0, centerRow - 3); r <= Math.min(GRID_SIZE - 1, centerRow + 3); r++) {
for (var c = Math.max(0, centerCol - 3); c <= Math.min(GRID_SIZE - 1, centerCol + 3); c++) {
if (grid[r][c] && grid[r][c] !== eternalCandy) {
attractedCandies.push(grid[r][c]);
grid[r][c] = null; // Remove from grid immediately
}
}
}
// Animate attraction of candies to eternal candy
for (var i = 0; i < attractedCandies.length; i++) {
(function (targetCandy, index) {
if (targetCandy && targetCandy.parent) {
// Animate candy moving to eternal candy
tween(targetCandy, {
x: eternalCandy.x,
y: eternalCandy.y,
scaleX: 0.2,
scaleY: 0.2,
alpha: 0.8
}, {
duration: 900 + index * 40,
easing: tween.easeIn,
onFinish: function onFinish() {
if (targetCandy && targetCandy.parent) {
// Explode with 80% bonus store points
var bonusScore = Math.floor(15 * comboMultiplier * 1.8);
var bonusGold = Math.floor(8 * 1.8);
if (comboMultiplier > 1) {
bonusGold += Math.floor(10 * 1.8);
}
score += bonusScore;
gold += bonusGold;
targetCandy.explode();
}
}
});
}
})(attractedCandies[i], i);
}
// Create visual eternal implosion effect
tween(eternalCandy.graphics, {
scaleX: 3.0,
scaleY: 3.0,
alpha: 0.4,
rotation: Math.PI * 6
}, {
duration: 1400,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Massive explosion after attraction
LK.effects.flashScreen(0xFFD700, 1200);
// Add score bonus for eternal activation
score += Math.floor(35000 * 1.8);
gold += Math.floor(17500 * 1.8);
updateUI();
// Clean up the eternal candy
if (eternalCandy && eternalCandy.parent) {
eternalCandy.parent.removeChild(eternalCandy);
}
grid[centerRow][centerCol] = null;
// Remove from eternal positions
for (var i = 0; i < eternalCandies.length; i++) {
if (eternalCandies[i].row === centerRow && eternalCandies[i].col === centerCol) {
eternalCandies.splice(i, 1);
break;
}
}
// Drop new candies after explosion
LK.setTimeout(function () {
dropCandies();
LK.setTimeout(function () {
processMatches();
}, 300);
}, 500);
}
});
}
// Helper: trigger void attraction and explosion in 4x4 area with 60% bonus
function triggerVoid4x4Attraction(voidCandy) {
if (!voidCandy || !voidCandy.parent) return;
var centerRow = voidCandy.row;
var centerCol = voidCandy.col;
// Collect all candies in 4x4 area around void (2 cells in each direction)
var attractedCandies = [];
for (var r = Math.max(0, centerRow - 2); r <= Math.min(GRID_SIZE - 1, centerRow + 2); r++) {
for (var c = Math.max(0, centerCol - 2); c <= Math.min(GRID_SIZE - 1, centerCol + 2); c++) {
if (grid[r][c] && grid[r][c] !== voidCandy) {
attractedCandies.push(grid[r][c]);
grid[r][c] = null; // Remove from grid immediately
}
}
}
// Animate attraction of candies to void
for (var i = 0; i < attractedCandies.length; i++) {
(function (targetCandy, index) {
if (targetCandy && targetCandy.parent) {
// Animate candy moving to void
tween(targetCandy, {
x: voidCandy.x,
y: voidCandy.y,
scaleX: 0.3,
scaleY: 0.3,
alpha: 0.7
}, {
duration: 800 + index * 50,
easing: tween.easeIn,
onFinish: function onFinish() {
if (targetCandy && targetCandy.parent) {
// Explode with 60% bonus store points
var bonusScore = Math.floor(15 * comboMultiplier * 1.6);
var bonusGold = Math.floor(8 * 1.6);
if (comboMultiplier > 1) {
bonusGold += Math.floor(10 * 1.6);
}
score += bonusScore;
gold += bonusGold;
targetCandy.explode();
}
}
});
}
})(attractedCandies[i], i);
}
// Create visual void implosion effect
tween(voidCandy.graphics, {
scaleX: 2.5,
scaleY: 2.5,
alpha: 0.5,
rotation: Math.PI * 4
}, {
duration: 1200,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Massive explosion after attraction
LK.effects.flashScreen(0x6e00ff, 1000);
// Add score bonus for void activation
score += Math.floor(25000 * 1.6);
gold += Math.floor(12500 * 1.6);
updateUI();
// Clean up the void
if (voidCandy && voidCandy.parent) {
voidCandy.parent.removeChild(voidCandy);
}
grid[centerRow][centerCol] = null;
// Remove from void positions
for (var i = 0; i < voidPositions.length; i++) {
if (voidPositions[i].row === centerRow && voidPositions[i].col === centerCol) {
voidPositions.splice(i, 1);
break;
}
}
// Drop new candies after explosion
LK.setTimeout(function () {
dropCandies();
LK.setTimeout(function () {
processMatches();
}, 300);
}, 500);
}
});
}
// Helper: trigger void attraction and explosion in 3x3 area
function triggerVoidAttraction() {
// Find all void candies
var allVoids = getAllVoidCandies();
if (allVoids.length === 0) return;
// Choose a central void as the attraction point
var centralVoid = allVoids[Math.floor(allVoids.length / 2)];
var centerRow = centralVoid.row;
var centerCol = centralVoid.col;
// Collect all candies in 3x3 area around central void
var attractedCandies = [];
for (var r = Math.max(0, centerRow - 1); r <= Math.min(GRID_SIZE - 1, centerRow + 1); r++) {
for (var c = Math.max(0, centerCol - 1); c <= Math.min(GRID_SIZE - 1, centerCol + 1); c++) {
if (grid[r][c] && grid[r][c] !== centralVoid) {
attractedCandies.push(grid[r][c]);
grid[r][c] = null; // Remove from grid immediately
}
}
}
// Animate attraction of candies to central void
for (var i = 0; i < attractedCandies.length; i++) {
(function (targetCandy, index) {
if (targetCandy && targetCandy.parent) {
// Animate candy moving to central void
tween(targetCandy, {
x: centralVoid.x,
y: centralVoid.y,
scaleX: 0.3,
scaleY: 0.3,
alpha: 0.7
}, {
duration: 800 + index * 50,
easing: tween.easeIn,
onFinish: function onFinish() {
if (targetCandy && targetCandy.parent) {
explodeCandyWithScore(targetCandy);
}
}
});
}
})(attractedCandies[i], i);
}
// Create visual void implosion effect
tween(centralVoid.graphics, {
scaleX: 2.5,
scaleY: 2.5,
alpha: 0.5,
rotation: Math.PI * 4
}, {
duration: 1200,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Massive explosion after attraction
LK.effects.flashScreen(0x6e00ff, 1000);
// Add score bonus
score += 25000;
gold += 12500;
updateUI();
// Clean up the central void
if (centralVoid && centralVoid.parent) {
centralVoid.parent.removeChild(centralVoid);
}
grid[centerRow][centerCol] = null;
// Remove from void positions
for (var i = 0; i < voidPositions.length; i++) {
if (voidPositions[i].row === centerRow && voidPositions[i].col === centerCol) {
voidPositions.splice(i, 1);
break;
}
}
// Drop new candies after explosion
LK.setTimeout(function () {
dropCandies();
LK.setTimeout(function () {
processMatches();
}, 300);
}, 500);
}
});
}
// Helper: handle 4-void combo (map clear)
function handleFourVoidCombo(matchArr) {
// Check if all are voids and length is 4
if (matchArr.length === 4 && matchArr.every(isVoidCandy)) {
// Clear the entire map
for (var row = 0; row < GRID_SIZE; row++) {
for (var col = 0; col < GRID_SIZE; col++) {
if (grid[row][col] && grid[row][col].parent) {
grid[row][col].parent.removeChild(grid[row][col]);
}
grid[row][col] = null;
}
}
clearAllVoids();
// Add massive store points
score += 8474477;
gold += 8474477;
updateUI();
// Visual effect
LK.effects.flashScreen(0x6e00ff, 2000);
var voidText = new Text2('VOID APOCALYPSE! +8474477', {
size: 120,
fill: '#6e00ff'
});
voidText.anchor.set(0.5, 0.5);
voidText.x = 1024;
voidText.y = 1366;
voidText.alpha = 0;
game.addChild(voidText);
tween(voidText, {
alpha: 1,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 800,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(voidText, {
alpha: 0
}, {
duration: 800,
onFinish: function onFinish() {
if (voidText.parent) voidText.parent.removeChild(voidText);
}
});
}, 2000);
}
});
return true;
}
return false;
}
// Main menu system variables
var gameState = 'menu'; // 'menu', 'playing', 'settings'
var mainMenuContainer = null;
var settingsMenuContainer = null;
var statisticsMenuContainer = null;
var gameContainer = null;
// Achievement system variables
var achievements = {
smallCollector: false,
hiddenStars: false,
leagues: false,
universe: false
};
var ballsClickedSmall = []; // Track which balls have been clicked to small size
var totalBallsToClick = 0; // Total number of balls that need to be clicked small
// Hidden Stars achievement variables
var hiddenStarsSequence = []; // Track the sequence entered after clicking shooting star
var hiddenStarsActivated = false; // Track if shooting star was clicked
// Save system variables
var saveButtonPressed = false;
var gameStateSaved = false;
var savesMenuContainer = null;
var savesMenuMode = 'save'; // 'save' or 'load'
// Create animated starfield background
var starField = new StarField();
game.addChild(starField);
// Create main menu
function createMainMenu() {
mainMenuContainer = new Container();
game.addChild(mainMenuContainer);
// Game title
var titleText = new Text2('ŞEKERLERI PATLAT', {
size: 140,
fill: '#FFD700'
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 800;
mainMenuContainer.addChild(titleText);
// Start Game button
var startButton = LK.getAsset('progressBarBg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.0,
scaleY: 1.5
});
startButton.x = 1024;
startButton.y = 1200;
mainMenuContainer.addChild(startButton);
var startButtonText = new Text2('OYUNA BAŞLA', {
size: 80,
fill: '#FFFFFF'
});
startButtonText.anchor.set(0.5, 0.5);
startButtonText.x = 1024;
startButtonText.y = 1200;
mainMenuContainer.addChild(startButtonText);
// Settings button
var settingsButton = LK.getAsset('progressBarBg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.0,
scaleY: 1.5
});
settingsButton.x = 1024;
settingsButton.y = 1500;
mainMenuContainer.addChild(settingsButton);
var settingsButtonText = new Text2('AYARLAR', {
size: 80,
fill: '#FFFFFF'
});
settingsButtonText.anchor.set(0.5, 0.5);
settingsButtonText.x = 1024;
settingsButtonText.y = 1500;
mainMenuContainer.addChild(settingsButtonText);
// Statistics button
var statisticsButton = LK.getAsset('progressBarBg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.0,
scaleY: 1.5
});
statisticsButton.x = 1024;
statisticsButton.y = 1800;
mainMenuContainer.addChild(statisticsButton);
var statisticsButtonText = new Text2('İSTATİSTİKLER', {
size: 80,
fill: '#FFFFFF'
});
statisticsButtonText.anchor.set(0.5, 0.5);
statisticsButtonText.x = 1024;
statisticsButtonText.y = 1800;
mainMenuContainer.addChild(statisticsButtonText);
// New Game button
var newGameButton = LK.getAsset('progressBarBg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.0,
scaleY: 1.5
});
newGameButton.x = 1024;
newGameButton.y = 2100;
mainMenuContainer.addChild(newGameButton);
var newGameButtonText = new Text2('YENİ OYUN', {
size: 80,
fill: '#FFFFFF'
});
newGameButtonText.anchor.set(0.5, 0.5);
newGameButtonText.x = 1024;
newGameButtonText.y = 2100;
mainMenuContainer.addChild(newGameButtonText);
// Saves button
var savesButton = LK.getAsset('progressBarBg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.0,
scaleY: 1.5
});
savesButton.x = 1024;
savesButton.y = 2400;
mainMenuContainer.addChild(savesButton);
var savesButtonText = new Text2('KAYITLAR', {
size: 80,
fill: '#FFFFFF'
});
savesButtonText.anchor.set(0.5, 0.5);
savesButtonText.x = 1024;
savesButtonText.y = 2400;
mainMenuContainer.addChild(savesButtonText);
// Store button references for click detection
mainMenuContainer.startButton = startButton;
mainMenuContainer.settingsButton = settingsButton;
mainMenuContainer.statisticsButton = statisticsButton;
mainMenuContainer.newGameButton = newGameButton;
mainMenuContainer.savesButton = savesButton;
}
// Create saves menu
function createSavesMenu() {
savesMenuContainer = new Container();
game.addChild(savesMenuContainer);
savesMenuContainer.alpha = 0;
// Saves title - changes based on mode
var titleText = savesMenuMode === 'load' ? 'KAYIT SEÇİN' : 'KAYITLAR';
var savesTitle = new Text2(titleText, {
size: 120,
fill: '#FFD700'
});
savesTitle.anchor.set(0.5, 0.5);
savesTitle.x = 1024;
savesTitle.y = 400;
savesMenuContainer.addChild(savesTitle);
// Create 4 save slots arranged in 2x2 grid
var saveSlots = [];
var slotPositions = [{
x: 650,
y: 800
},
// Top left
{
x: 1398,
y: 800
},
// Top right
{
x: 650,
y: 1400
},
// Bottom left
{
x: 1398,
y: 1400
} // Bottom right
];
for (var i = 0; i < 4; i++) {
// Create save slot background
var slotBg = LK.getAsset('progressBarBg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.8,
scaleY: 2.5
});
slotBg.x = slotPositions[i].x;
slotBg.y = slotPositions[i].y;
savesMenuContainer.addChild(slotBg);
// Check if there's a saved game for this slot
var slotPrefix = 'saveSlot' + (i + 1) + '_';
var hasSave = storage[slotPrefix + 'hasSave'];
var slotText = '';
var scoreText = '';
var levelText = '';
if (hasSave) {
// Slot has saved data
slotText = 'Slot ' + (i + 1);
scoreText = 'Score: ' + (storage[slotPrefix + 'score'] || 0);
levelText = 'Level: ' + (storage[slotPrefix + 'level'] || 1);
} else {
// Empty slot
slotText = 'Slot ' + (i + 1);
scoreText = 'Empty';
levelText = '';
}
// Slot number text
var slotNumberText = new Text2(slotText, {
size: 60,
fill: '#FFD700'
});
slotNumberText.anchor.set(0.5, 0.5);
slotNumberText.x = slotPositions[i].x;
slotNumberText.y = slotPositions[i].y - 80;
savesMenuContainer.addChild(slotNumberText);
// Score text
var slotScoreText = new Text2(scoreText, {
size: 50,
fill: '#FFFFFF'
});
slotScoreText.anchor.set(0.5, 0.5);
slotScoreText.x = slotPositions[i].x;
slotScoreText.y = slotPositions[i].y - 20;
savesMenuContainer.addChild(slotScoreText);
// Level text
if (levelText) {
var slotLevelText = new Text2(levelText, {
size: 50,
fill: '#FFFFFF'
});
slotLevelText.anchor.set(0.5, 0.5);
slotLevelText.x = slotPositions[i].x;
slotLevelText.y = slotPositions[i].y + 40;
savesMenuContainer.addChild(slotLevelText);
}
// Store slot data for click detection
saveSlots.push({
background: slotBg,
slotIndex: i,
x: slotPositions[i].x,
y: slotPositions[i].y,
hasSave: !!hasSave
});
}
// Back button
var backButton = LK.getAsset('progressBarBg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.2
});
backButton.x = 1024;
backButton.y = 1800;
savesMenuContainer.addChild(backButton);
var backButtonText = new Text2('GERİ', {
size: 70,
fill: '#FFFFFF'
});
backButtonText.anchor.set(0.5, 0.5);
backButtonText.x = 1024;
backButtonText.y = 1800;
savesMenuContainer.addChild(backButtonText);
// Store button and slots references for click detection
savesMenuContainer.backButton = backButton;
savesMenuContainer.saveSlots = saveSlots;
}
// Create statistics menu
function createStatisticsMenu() {
statisticsMenuContainer = new Container();
game.addChild(statisticsMenuContainer);
statisticsMenuContainer.alpha = 0;
// Statistics title
var statisticsTitle = new Text2('İSTATİSTİKLER', {
size: 120,
fill: '#FFD700'
});
statisticsTitle.anchor.set(0.5, 0.5);
statisticsTitle.x = 1024;
statisticsTitle.y = 400;
statisticsMenuContainer.addChild(statisticsTitle);
// Get statistics from storage
var highestScore = storage.highestScore || 0;
var highestLevel = storage.highestLevel || 1;
var totalGold = storage.totalGoldEarned || 0;
var gamesPlayed = storage.gamesPlayed || 0;
var achievementsUnlocked = 0;
// Count achievements
if (storage.smallCollectorAchieved) achievementsUnlocked++;
if (storage.hiddenStarsAchieved) achievementsUnlocked++;
if (storage.leaguesAchieved) achievementsUnlocked++;
if (storage.universeAchieved) achievementsUnlocked++;
// Display statistics
var yPosition = 600;
var spacing = 120;
// Highest Score
var scoreStatText = new Text2('En Yüksek Skor: ' + highestScore, {
size: 60,
fill: '#FFFFFF'
});
scoreStatText.anchor.set(0.5, 0.5);
scoreStatText.x = 1024;
scoreStatText.y = yPosition;
statisticsMenuContainer.addChild(scoreStatText);
// Highest Level
var levelStatText = new Text2('En Yüksek Seviye: ' + highestLevel, {
size: 60,
fill: '#FFFFFF'
});
levelStatText.anchor.set(0.5, 0.5);
levelStatText.x = 1024;
levelStatText.y = yPosition + spacing;
statisticsMenuContainer.addChild(levelStatText);
// Total Gold
var goldStatText = new Text2('Toplam Altın: ' + totalGold, {
size: 60,
fill: '#FFD700'
});
goldStatText.anchor.set(0.5, 0.5);
goldStatText.x = 1024;
goldStatText.y = yPosition + spacing * 2;
statisticsMenuContainer.addChild(goldStatText);
// Games Played
var gamesStatText = new Text2('Oynanan Oyunlar: ' + gamesPlayed, {
size: 60,
fill: '#FFFFFF'
});
gamesStatText.anchor.set(0.5, 0.5);
gamesStatText.x = 1024;
gamesStatText.y = yPosition + spacing * 3;
statisticsMenuContainer.addChild(gamesStatText);
// Achievements
var achievementStatText = new Text2('Başarımlar: ' + achievementsUnlocked + '/4', {
size: 60,
fill: '#00FF00'
});
achievementStatText.anchor.set(0.5, 0.5);
achievementStatText.x = 1024;
achievementStatText.y = yPosition + spacing * 4;
statisticsMenuContainer.addChild(achievementStatText);
// Player Names Section
var playerNamesTitle = new Text2('Oyuncular:', {
size: 70,
fill: '#FFD700'
});
playerNamesTitle.anchor.set(0.5, 0.5);
playerNamesTitle.x = 1024;
playerNamesTitle.y = yPosition + spacing * 5.5;
statisticsMenuContainer.addChild(playerNamesTitle);
// Get all player names from storage (stored as an array)
var playerNames = storage.playerNames || [];
// Create a display text that shows all players publicly to everyone
var displayText = playerNames.length > 0 ? 'Tüm Oyuncular: ' + playerNames.join(', ') : 'Henüz oyuncu yok';
// Allow longer text to show more player names
if (displayText.length > 80) {
displayText = displayText.substring(0, 80) + '...';
}
var playerNamesText = new Text2(displayText, {
size: 45,
fill: '#FFFFFF'
});
playerNamesText.anchor.set(0.5, 0.5);
playerNamesText.x = 1024;
playerNamesText.y = yPosition + spacing * 6.5;
statisticsMenuContainer.addChild(playerNamesText);
// Back button
var backButton = LK.getAsset('progressBarBg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.2
});
backButton.x = 1024;
backButton.y = 1800;
statisticsMenuContainer.addChild(backButton);
var backButtonText = new Text2('GERİ', {
size: 70,
fill: '#FFFFFF'
});
backButtonText.anchor.set(0.5, 0.5);
backButtonText.x = 1024;
backButtonText.y = 1800;
statisticsMenuContainer.addChild(backButtonText);
// Store button reference for click detection
statisticsMenuContainer.backButton = backButton;
}
// Create settings menu
function createSettingsMenu() {
settingsMenuContainer = new Container();
game.addChild(settingsMenuContainer);
settingsMenuContainer.alpha = 0;
// Settings title
var settingsTitle = new Text2('AYARLAR', {
size: 120,
fill: '#FFD700'
});
settingsTitle.anchor.set(0.5, 0.5);
settingsTitle.x = 1024;
settingsTitle.y = 600;
settingsMenuContainer.addChild(settingsTitle);
// Music volume info (since LK handles music automatically)
var musicText = new Text2('Müzik: Otomatik', {
size: 60,
fill: '#FFFFFF'
});
musicText.anchor.set(0.5, 0.5);
musicText.x = 1024;
musicText.y = 1000;
settingsMenuContainer.addChild(musicText);
// Sound effects info
var soundText = new Text2('Ses Efektleri: Açık', {
size: 60,
fill: '#FFFFFF'
});
soundText.anchor.set(0.5, 0.5);
soundText.x = 1024;
soundText.y = 1150;
settingsMenuContainer.addChild(soundText);
// Back button
var backButton = LK.getAsset('progressBarBg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.2
});
backButton.x = 1024;
backButton.y = 1800;
settingsMenuContainer.addChild(backButton);
var backButtonText = new Text2('GERİ', {
size: 70,
fill: '#FFFFFF'
});
backButtonText.anchor.set(0.5, 0.5);
backButtonText.x = 1024;
backButtonText.y = 1800;
settingsMenuContainer.addChild(backButtonText);
// Store button reference for click detection
settingsMenuContainer.backButton = backButton;
}
// Create game container to hold all game elements
function createGameContainer() {
gameContainer = new Container();
game.addChild(gameContainer);
gameContainer.alpha = 0;
}
// Initialize menus
createMainMenu();
createSettingsMenu();
createStatisticsMenu();
createSavesMenu();
createGameContainer();
// Create grid background
var gridBg = game.attachAsset('gridBackground', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1366
});
gameContainer.addChild(gridBg);
// Create grid lines
for (var i = 0; i <= GRID_SIZE; i++) {
// Vertical lines
var verticalLine = LK.getAsset('gridLine', {
width: 4,
height: GRID_SIZE * CELL_SIZE,
color: 0x000000,
shape: 'box',
anchorX: 0.5,
anchorY: 0.5,
x: GRID_START_X + i * CELL_SIZE,
y: GRID_START_Y + GRID_SIZE * CELL_SIZE / 2
});
gameContainer.addChild(verticalLine);
// Horizontal lines
var horizontalLine = LK.getAsset('gridLine', {
width: GRID_SIZE * CELL_SIZE,
height: 4,
color: 0x000000,
shape: 'box',
anchorX: 0.5,
anchorY: 0.5,
x: GRID_START_X + GRID_SIZE * CELL_SIZE / 2,
y: GRID_START_Y + i * CELL_SIZE
});
gameContainer.addChild(horizontalLine);
}
// Create UI elements
var scoreText = new Text2('Score: 0', {
size: 80,
fill: '#FFFFFF'
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
scoreText.y = 100;
var levelText = new Text2('Level: 1', {
size: 60,
fill: '#FFFFFF'
});
levelText.anchor.set(0, 0);
LK.gui.topLeft.addChild(levelText);
levelText.x = 120;
levelText.y = 100;
var goldText = new Text2('Gold: 0', {
size: 60,
fill: '#FFD700'
});
goldText.anchor.set(1, 0);
LK.gui.topRight.addChild(goldText);
goldText.x = -20;
goldText.y = 100;
// Create hourglass display
var hourglassText = new Text2('Hourglass: 0', {
size: 50,
fill: '#FFD700'
});
hourglassText.anchor.set(1, 0);
LK.gui.topRight.addChild(hourglassText);
hourglassText.x = -20;
hourglassText.y = 170;
// Create combo display text
var comboText = new Text2('', {
size: 100,
fill: '#FFFF00'
});
comboText.anchor.set(0.5, 0.5);
LK.gui.center.addChild(comboText);
comboText.alpha = 0; // Start invisible
// Create level progress bar
var progressBarBg = LK.getAsset('progressBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
LK.gui.top.addChild(progressBarBg);
progressBarBg.y = 200;
var progressBarFill = LK.getAsset('progressBarFill', {
anchorX: 0,
anchorY: 0.5
});
progressBarBg.addChild(progressBarFill);
progressBarFill.x = -300; // Start from left edge of background
progressBarFill.scaleX = 0; // Start empty
// Initialize grid
function initializeGrid() {
grid = [];
for (var row = 0; row < GRID_SIZE; row++) {
grid[row] = [];
for (var col = 0; col < GRID_SIZE; col++) {
// Normal candy creation with 5% chance for purple
var color;
if (Math.random() < 0.05) {
// 5% chance for purple fruit
color = 'purple';
} else {
color = COLORS[Math.floor(Math.random() * COLORS.length)];
}
var candy = new Candy(color, row, col);
candy.x = GRID_START_X + col * CELL_SIZE + CELL_SIZE / 2;
candy.y = GRID_START_Y + row * CELL_SIZE + CELL_SIZE / 2;
grid[row][col] = candy;
gameContainer.addChild(candy);
}
}
}
function removeInitialMatches() {
var hasMatches = true;
while (hasMatches) {
hasMatches = false;
for (var row = 0; row < GRID_SIZE; row++) {
for (var col = 0; col < GRID_SIZE; col++) {
if (checkMatch(row, col).length >= 3) {
hasMatches = true;
// Random color with 5% chance for purple
var randomColor;
if (Math.random() < 0.05) {
// 5% chance for purple fruit
randomColor = 'purple';
} else {
randomColor = COLORS[Math.floor(Math.random() * COLORS.length)];
}
grid[row][col].type = randomColor;
grid[row][col].removeChild(grid[row][col].graphics);
var assetMap = {
'blue': 'blueCandy',
'red': 'redCandy',
'green': 'greenCandy',
'orange': 'orangeCandy',
'purple': 'purpleCandy'
};
grid[row][col].graphics = grid[row][col].attachAsset(assetMap[randomColor], {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
});
}
}
}
}
}
function getCandyAt(x, y) {
var col = Math.floor((x - GRID_START_X) / CELL_SIZE);
var row = Math.floor((y - GRID_START_Y) / CELL_SIZE);
if (row >= 0 && row < GRID_SIZE && col >= 0 && col < GRID_SIZE && grid[row] && grid[row][col]) {
return grid[row][col];
}
return null;
}
function swapCandies(candy1, candy2) {
if (!candy1 || !candy2 || candy1 === candy2) return false;
var row1 = candy1.row,
col1 = candy1.col;
var row2 = candy2.row,
col2 = candy2.col;
// Check if adjacent
var dx = Math.abs(col1 - col2);
var dy = Math.abs(row1 - row2);
if (dx + dy !== 1) return false;
// Swap in grid
grid[row1][col1] = candy2;
grid[row2][col2] = candy1;
// Update candy properties
candy1.row = row2;
candy1.col = col2;
candy2.row = row1;
candy2.col = col1;
// Animate swap
tween(candy1, {
x: GRID_START_X + col2 * CELL_SIZE + CELL_SIZE / 2,
y: GRID_START_Y + row2 * CELL_SIZE + CELL_SIZE / 2
}, {
duration: 150,
easing: tween.easeOut
});
tween(candy2, {
x: GRID_START_X + col1 * CELL_SIZE + CELL_SIZE / 2,
y: GRID_START_Y + row1 * CELL_SIZE + CELL_SIZE / 2
}, {
duration: 150,
easing: tween.easeOut
});
return true;
}
function checkMatch(row, col) {
if (!grid[row] || !grid[row][col]) return [];
var candy = grid[row][col];
var matches = [candy];
var type = candy.type;
// Check horizontal
for (var c = col - 1; c >= 0 && grid[row][c] && grid[row][c].type === type; c--) {
matches.unshift(grid[row][c]);
}
for (var c = col + 1; c < GRID_SIZE && grid[row][c] && grid[row][c].type === type; c++) {
matches.push(grid[row][c]);
}
if (matches.length >= 3) return matches;
// Check vertical
matches = [candy];
for (var r = row - 1; r >= 0 && grid[r][col] && grid[r][col].type === type; r--) {
matches.unshift(grid[r][col]);
}
for (var r = row + 1; r < GRID_SIZE && grid[r][col] && grid[r][col].type === type; r++) {
matches.push(grid[r][col]);
}
return matches.length >= 3 ? matches : [];
}
function findAllMatches() {
var allMatches = [];
var processed = [];
for (var row = 0; row < GRID_SIZE; row++) {
processed[row] = [];
for (var col = 0; col < GRID_SIZE; col++) {
processed[row][col] = false;
}
}
for (var row = 0; row < GRID_SIZE; row++) {
for (var col = 0; col < GRID_SIZE; col++) {
if (!processed[row][col]) {
var matches = checkMatch(row, col);
if (matches.length >= 3) {
allMatches.push(matches);
for (var i = 0; i < matches.length; i++) {
processed[matches[i].row][matches[i].col] = true;
}
}
}
}
}
return allMatches;
}
function check4x4Formations() {
var formationsFound = false;
// Check all possible 4x4 positions
for (var row = 0; row <= GRID_SIZE - 4; row++) {
for (var col = 0; col <= GRID_SIZE - 4; col++) {
// Check if all 16 positions in the 4x4 area have candies of same type
var firstCandy = grid[row][col];
if (!firstCandy) continue;
var sameType = true;
var formationCandies = [];
// Check all positions in the 4x4 area
for (var r = row; r < row + 4; r++) {
for (var c = col; c < col + 4; c++) {
var currentCandy = grid[r][c];
if (!currentCandy || currentCandy.type !== firstCandy.type) {
sameType = false;
break;
}
formationCandies.push(currentCandy);
}
if (!sameType) break;
}
if (sameType && formationCandies.length === 16) {
// Found a 4x4 formation - trigger horizontal and vertical clearing
formationsFound = true;
// Get the center position of the 4x4 formation
var centerRow = row + 1;
var centerCol = col + 2;
// Clear entire row of the center
for (var c = 0; c < GRID_SIZE; c++) {
if (grid[centerRow][c] && grid[centerRow][c] !== null) {
explodeCandyWithScore(grid[centerRow][c]);
grid[centerRow][c] = null;
}
}
// Clear entire column of the center
for (var r = 0; r < GRID_SIZE; r++) {
if (grid[r][centerCol] && grid[r][centerCol] !== null) {
explodeCandyWithScore(grid[r][centerCol]);
grid[r][centerCol] = null;
}
}
// Add massive bonus for 4x4 formation
score += 5000;
gold += 2500;
comboMultiplier += 10;
updateUI();
// Create spectacular visual effect
LK.effects.flashScreen(0xFFD700, 1000);
LK.getSound('powerup').play();
// Break out of loops since we found a formation
return formationsFound;
}
}
}
return formationsFound;
}
function checkBlackHoleCombinations() {
var combinationsFound = false;
// Check all grid positions for adjacent black holes
for (var row = 0; row < GRID_SIZE; row++) {
for (var col = 0; col < GRID_SIZE; col++) {
var candy = grid[row][col];
if (candy && candy.isSpecial && candy.specialType === 'blackHole') {
// Check adjacent positions for other black holes
var adjacentPositions = [[-1, 0], [1, 0], [0, -1], [0, 1]];
for (var a = 0; a < adjacentPositions.length; a++) {
var adjRow = row + adjacentPositions[a][0];
var adjCol = col + adjacentPositions[a][1];
if (adjRow >= 0 && adjRow < GRID_SIZE && adjCol >= 0 && adjCol < GRID_SIZE) {
var adjacentCandy = grid[adjRow][adjCol];
if (adjacentCandy && adjacentCandy.isSpecial && adjacentCandy.specialType === 'blackHole') {
// Found two adjacent black holes - combine them into supernova
combinationsFound = true;
// Invalidate special properties of both black holes before combining
candy.isSpecial = false;
candy.specialType = null;
adjacentCandy.isSpecial = false;
adjacentCandy.specialType = null;
// Transform first black hole into supernova
candy.makeSpecial('supernova');
// Remove second black hole
grid[adjRow][adjCol] = null;
adjacentCandy.explode();
// Ensure the supernova stays in the grid and is not processed for removal
candy.justCreated = true;
// Create spectacular combination effect
tween(candy.graphics, {
scaleX: 2.5,
scaleY: 2.5,
tint: 0xFFD700,
rotation: Math.PI * 6
}, {
duration: 1500,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Add continuous pulsing glow effect
var _pulseSuperNova2 = function pulseSuperNova() {
if (candy && candy.isSpecial && candy.specialType === 'supernova' && candy.parent) {
tween(candy.graphics, {
scaleX: 1.5,
scaleY: 1.5,
tint: 0xFFFF00
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(candy.graphics, {
scaleX: 1.3,
scaleY: 1.3,
tint: 0xFFFFFF
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
LK.setTimeout(_pulseSuperNova2, 200);
}
});
}
});
}
};
_pulseSuperNova2();
LK.effects.flashScreen(0xFFD700, 800);
}
});
// Add bonus score for combination
score += 3000;
gold += 1500;
updateUI();
LK.getSound('powerup').play();
// Skip checking other adjacent positions for this candy
break;
}
}
}
}
}
}
return combinationsFound;
}
function processMatches() {
var allMatches = findAllMatches();
if (allMatches.length === 0) {
// Check if this was a cascade (not user-initiated)
var currentTime = Date.now();
if (currentTime - lastCascadeTime < 2000 && cascadeComboCount > 0) {
// This was part of a cascade sequence, don't reset cascade combo yet
// Reset cascade combo after a delay if no more matches found
LK.setTimeout(function () {
// Save current combo count before resetting
if (cascadeComboCount > savedComboCount) {
savedComboCount = cascadeComboCount;
}
// Only reset if not in hourglass super combo mode
if (savedComboCount < 3) {
cascadeComboCount = 0;
} else {
// Keep combo at super combo level when hourglass is active
cascadeComboCount = savedComboCount;
}
}, 1000);
} else {
// Save current combo count before resetting
if (cascadeComboCount > savedComboCount) {
savedComboCount = cascadeComboCount;
}
// Only reset if not in hourglass super combo mode
if (savedComboCount < 3) {
cascadeComboCount = 0; // Reset if too much time passed or no cascade
} else {
// Keep combo at super combo level when hourglass is active
cascadeComboCount = savedComboCount;
}
}
comboMultiplier = 1;
showComboDisplay(); // Hide combo display when combo ends
isProcessing = false;
return;
}
// Check for timeless black hole combinations first
for (var m = 0; m < allMatches.length; m++) {
if (handleTimelessBlackHoleCombo(allMatches[m])) {
// Remove match to prevent further processing
allMatches[m].length = 0;
}
}
// Check for eternal candy combinations
for (var m = 0; m < allMatches.length; m++) {
var matches = allMatches[m];
// Find if any eternal candy is in this match
var eternalCandy = null;
for (var i = 0; i < matches.length; i++) {
if (isEternalCandy(matches[i])) {
eternalCandy = matches[i];
break;
}
}
if (eternalCandy && matches.length >= 3) {
// Eternal candy combo - trigger 6x6 attraction with 80% bonus
LK.setTimeout(function () {
triggerEternal6x6Attraction(eternalCandy);
}, 300);
// Clear match to prevent further processing
matches.length = 0;
}
}
// Check for timeless Karadeniz combinations first
checkTimelessKaradenizCombinations(allMatches);
// Process matches and create special candies
var totalScore = 0;
var totalGold = 0;
for (var m = 0; m < allMatches.length; m++) {
var matches = allMatches[m];
// --- VOID LOGIC: handle 4-void combo first ---
if (handleFourVoidCombo(matches)) {
// Remove all candies from this match to prevent further processing
matches.length = 0;
continue;
}
// --- VOID LOGIC: handle void combo (transform or spread) ---
if (handleVoidCombo(matches)) {
// Remove all candies from this match to prevent further processing
matches.length = 0;
continue;
}
var matchScore = matches.length * 10 * comboMultiplier;
var matchGold = matches.length * 5;
if (comboMultiplier > 1) {
matchGold += 50; // Combo bonus
}
totalScore += matchScore;
totalGold += matchGold;
// Check for special candy creation
if (matches.length >= 7) {
// Create supernova with visual effect but don't activate it
var centerCandy = matches[Math.floor(matches.length / 2)];
centerCandy.makeSpecial('supernova');
// Add creation sparkle effect
tween(centerCandy.graphics, {
scaleX: 1.3,
scaleY: 1.3,
tint: 0xFFFFFF
}, {
duration: 500,
easing: tween.bounceOut,
onFinish: function onFinish() {
// Add continuous pulsing glow effect
var _pulseSuperNova = function pulseSuperNova() {
if (centerCandy && centerCandy.isSpecial && centerCandy.specialType === 'supernova' && centerCandy.parent) {
tween(centerCandy.graphics, {
scaleX: 1.5,
scaleY: 1.5,
tint: 0xFFFF00
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(centerCandy.graphics, {
scaleX: 1.3,
scaleY: 1.3,
tint: 0xFFFFFF
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
LK.setTimeout(_pulseSuperNova, 200);
}
});
}
});
}
};
_pulseSuperNova();
}
});
// Don't remove the supernova from matches - keep it on the board
// Skip removing the supernova so it stays on the grid
var centerIndex = Math.floor(matches.length / 2);
matches.splice(centerIndex, 1);
} else if (matches.length >= 6) {
// Create disco ball with visual effect
var centerCandy = matches[Math.floor(matches.length / 2)];
centerCandy.makeSpecial('discoBall');
// Add creation sparkle effect
tween(centerCandy.graphics, {
scaleX: 1.0,
scaleY: 1.0,
rotation: Math.PI
}, {
duration: 300,
easing: tween.bounceOut
});
// Add continuous rotation to disco ball with optimized performance
var _rotateDiscoBall = function rotateDiscoBall() {
if (centerCandy.isSpecial && centerCandy.specialType === 'discoBall' && centerCandy.parent) {
tween(centerCandy.graphics, {
rotation: centerCandy.graphics.rotation + Math.PI * 2
}, {
duration: 6000,
// Slower rotation for better performance
easing: tween.linear,
onFinish: function onFinish() {
// Add delay before next rotation to reduce CPU load
LK.setTimeout(_rotateDiscoBall, 100);
}
});
}
};
_rotateDiscoBall();
matches.splice(Math.floor(matches.length / 2), 1);
} else if (matches.length === 5) {
// Create special based on color with unique effects
var centerCandy = matches[2];
var color = centerCandy.type;
var specialType;
if (color === 'blue') {
// Create converter instead of blueBomb for blue 5-match
centerCandy.makeSpecial('vriper'); // Use vriper as converter visual
centerCandy.specialType = 'converter'; // Set special type to converter
// Add converter creation effect
tween(centerCandy.graphics, {
scaleX: 1.2,
scaleY: 1.2,
tint: 0x4a90e2
}, {
duration: 500,
easing: tween.bounceOut,
onFinish: function onFinish() {
// Add pulsing blue glow effect for converter
var _pulseConverter = function pulseConverter() {
if (centerCandy.isSpecial && centerCandy.specialType === 'converter' && centerCandy.parent) {
tween(centerCandy.graphics, {
scaleX: 1.4,
scaleY: 1.4,
tint: 0x6ba3f0
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(centerCandy.graphics, {
scaleX: 1.2,
scaleY: 1.2,
tint: 0x4a90e2
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
LK.setTimeout(_pulseConverter, 100);
}
});
}
});
}
};
_pulseConverter();
}
});
} else if (color === 'red') {
specialType = 'redRocket';
} else if (color === 'green') {
specialType = 'greenPentagon';
} else if (color === 'orange') {
specialType = 'orangeLollipop';
} else if (color === 'purple') {
// Check if this is purple candy - create black hole instead
centerCandy.makeSpecial('blackHole');
// Add black hole creation effect
tween(centerCandy.graphics, {
scaleX: 1.2,
scaleY: 1.2,
alpha: 0.8
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Add pulsing animation to black hole
var _pulseBlackHole2 = function _pulseBlackHole() {
if (centerCandy.isSpecial && centerCandy.specialType === 'blackHole' && centerCandy.parent) {
tween(centerCandy.graphics, {
scaleX: 1.4,
scaleY: 1.4,
alpha: 0.6
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(centerCandy.graphics, {
scaleX: 1.2,
scaleY: 1.2,
alpha: 0.8
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
LK.setTimeout(_pulseBlackHole2, 100);
}
});
}
});
}
};
_pulseBlackHole2();
}
});
} else {
specialType = 'purpleBerry';
}
if (color !== 'purple' && color !== 'blue') {
centerCandy.makeSpecial(specialType);
}
matches.splice(2, 1);
}
// Explode remaining matches with staggered timing to reduce simultaneous animations
for (var i = 0; i < matches.length; i++) {
var candy = matches[i];
var candyRow = candy.row;
var candyCol = candy.col;
grid[candy.row][candy.col] = null;
// Stagger explosions to reduce simultaneous tween load
(function (candyToExplode, delay) {
LK.setTimeout(function () {
candyToExplode.explode();
}, delay);
})(candy, i * 100);
}
}
score += totalScore;
gold += totalGold;
comboMultiplier += 5;
showComboDisplay(); // Show updated combo display
var newLevel = 1;
// Calculate required score for next level (50000 for level 2, then quadruple each time)
function getRequiredScoreForLevel(targetLevel) {
if (targetLevel <= 1) return 0;
if (targetLevel === 2) return 50000;
// For levels 3+: 50000 * 4^(level-2)
return 50000 * Math.pow(4, targetLevel - 2);
}
// Update level based on new progression system
while (score >= getRequiredScoreForLevel(newLevel + 1)) {
newLevel++;
}
if (newLevel > level) {
level = newLevel;
// Check for level 7 victory
if (level >= 7) {
// Start level 7 victory sequence
startLevel7Victory();
return;
}
// Level up animation - flash progress bar
tween(progressBarFill, {
tint: 0xFFFF00
}, {
duration: 200,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(progressBarFill, {
tint: 0x00FF00
}, {
duration: 200,
easing: tween.easeInOut
});
}
});
// Show level up notification
showLevelUpNotification(level);
// Add +1000 gold for each level completed
gold += 1000;
if (level % 5 === 0) {
gold += 4000;
}
// Check for Leagues achievement
checkLeaguesAchievement();
}
updateUI();
LK.getSound('match').play();
// Check for 4x4 formations before black hole combinations
check4x4Formations();
// Check for black hole combinations before dropping candies
checkBlackHoleCombinations();
// Track cascade combo if this was an auto-cascade (not user-initiated)
var currentTime = Date.now();
if (currentTime - lastCascadeTime < 2000 || lastCascadeTime === 0) {
// If hourglass is active and we're at super combo level, add to it instead of incrementing normally
if (savedComboCount >= 3 && cascadeComboCount >= 3) {
// Player is in hourglass super combo mode - add to the super combo
cascadeComboCount++;
} else {
cascadeComboCount++;
}
lastCascadeTime = currentTime;
// Show cascade combo display for levels 1-7
if (cascadeComboCount >= 1 && cascadeComboCount <= 7) {
showCascadeComboDisplay(cascadeComboCount);
}
// Special reward: Create supernova if reached 7th cascade combo
if (cascadeComboCount === 7) {
createSupernovaReward();
}
}
// Drop candies and continue processing
LK.setTimeout(function () {
dropCandies();
LK.setTimeout(function () {
processMatches();
}, 300);
}, 400);
}
function dropCandies() {
// Always ensure no empty squares remain by filling all null positions
for (var col = 0; col < GRID_SIZE; col++) {
var writeRow = GRID_SIZE - 1;
// Move existing candies down
for (var row = GRID_SIZE - 1; row >= 0; row--) {
if (grid[row] && grid[row][col] !== null && grid[row][col] !== undefined) {
// Move candy down to available position
if (row !== writeRow) {
var candyToMove = grid[row][col];
grid[writeRow][col] = candyToMove;
grid[row][col] = null;
if (candyToMove) {
candyToMove.row = writeRow;
candyToMove.col = col;
tween(candyToMove, {
y: GRID_START_Y + writeRow * CELL_SIZE + CELL_SIZE / 2
}, {
duration: 150,
easing: tween.easeOut
});
}
}
writeRow--;
}
}
// Create new candies for ALL empty spaces - ensuring no empty squares remain
for (var row = writeRow; row >= 0; row--) {
var candy;
if (onlySpecialCandies) {
// Create only special candies (disco ball, rocket, bomb, black hole, supernova)
var specialTypes = ['discoBall', 'redRocket', 'blueBomb', 'blackHole', 'supernova', 'expires', 'writerpir', 'vriper', 'converter'];
var randomSpecialType = specialTypes[Math.floor(Math.random() * specialTypes.length)];
var randomColor = COLORS[Math.floor(Math.random() * COLORS.length)];
candy = new Candy(randomColor, row, col);
candy.x = GRID_START_X + col * CELL_SIZE + CELL_SIZE / 2;
// Start candies above the visible grid area
var emptySpaces = writeRow + 1;
var startRow = row - emptySpaces;
candy.y = GRID_START_Y + startRow * CELL_SIZE + CELL_SIZE / 2;
// Make it special immediately
candy.makeSpecial(randomSpecialType);
// Check for Universe achievement if expires (Karadeniz) was created
if (randomSpecialType === 'expires') {
checkUniverseAchievement();
}
} else {
// Normal candy creation with 5% chance for purple
var randomColor;
if (Math.random() < 0.05) {
// 5% chance for purple fruit
randomColor = 'purple';
} else {
randomColor = COLORS[Math.floor(Math.random() * COLORS.length)];
}
candy = new Candy(randomColor, row, col);
candy.x = GRID_START_X + col * CELL_SIZE + CELL_SIZE / 2;
// Start candies above the visible grid area
var emptySpaces = writeRow + 1;
var startRow = row - emptySpaces;
candy.y = GRID_START_Y + startRow * CELL_SIZE + CELL_SIZE / 2;
}
grid[row][col] = candy;
gameContainer.addChild(candy);
// Animate falling with bounce effect
tween(candy, {
y: GRID_START_Y + row * CELL_SIZE + CELL_SIZE / 2
}, {
duration: 200 + (emptySpaces - (writeRow - row)) * 30,
easing: tween.bounceOut
});
}
}
// Double-check: Fill any remaining null positions (safety measure)
for (var row = 0; row < GRID_SIZE; row++) {
for (var col = 0; col < GRID_SIZE; col++) {
if (grid[row][col] === null) {
var candy;
if (onlySpecialCandies) {
var specialTypes = ['discoBall', 'redRocket', 'blueBomb', 'blackHole', 'supernova', 'expires', 'writerpir', 'vriper', 'converter'];
var randomSpecialType = specialTypes[Math.floor(Math.random() * specialTypes.length)];
var randomColor = COLORS[Math.floor(Math.random() * COLORS.length)];
candy = new Candy(randomColor, row, col);
candy.x = GRID_START_X + col * CELL_SIZE + CELL_SIZE / 2;
candy.y = GRID_START_Y - CELL_SIZE; // Start slightly above
candy.makeSpecial(randomSpecialType);
// Check for Universe achievement if expires (Karadeniz) was created
if (randomSpecialType === 'expires') {
checkUniverseAchievement();
}
} else {
// Normal candy creation with 5% chance for purple
var randomColor;
if (Math.random() < 0.05) {
// 5% chance for purple fruit
randomColor = 'purple';
} else {
randomColor = COLORS[Math.floor(Math.random() * COLORS.length)];
}
candy = new Candy(randomColor, row, col);
candy.x = GRID_START_X + col * CELL_SIZE + CELL_SIZE / 2;
candy.y = GRID_START_Y - CELL_SIZE; // Start slightly above
}
grid[row][col] = candy;
gameContainer.addChild(candy);
// Animate to final position
tween(candy, {
y: GRID_START_Y + row * CELL_SIZE + CELL_SIZE / 2
}, {
duration: 250,
easing: tween.bounceOut
});
}
}
}
// Add special bonus if entire grid was cleared
var totalCandies = 0;
for (var checkRow = 0; checkRow < GRID_SIZE; checkRow++) {
for (var checkCol = 0; checkCol < GRID_SIZE; checkCol++) {
if (grid[checkRow][checkCol] !== null) {
totalCandies++;
}
}
}
if (totalCandies === GRID_SIZE * GRID_SIZE) {
// Grid was completely refilled - give bonus
score += 5000;
gold += 2500;
updateUI();
LK.effects.flashScreen(0xFFD700, 500); // Gold flash for complete refill
}
}
function explodeCandyWithScore(candy) {
if (!candy || !candy.parent) return;
// Add score and gold for each exploding candy
var candyScore = 15 * comboMultiplier;
var candyGold = 8;
if (comboMultiplier > 1) {
candyGold += 10; // Combo bonus
}
score += candyScore;
gold += candyGold;
// Stop any existing tweens on this candy to prevent conflicts
tween.stop(candy);
if (candy.graphics) {
tween.stop(candy.graphics);
}
// Explode the candy
candy.explode();
}
function showComboDisplay() {
if (comboMultiplier > 1) {
// Update combo text
comboText.setText('COMBO x' + comboMultiplier);
// Show combo text with scale animation
comboText.alpha = 1;
comboText.scaleX = 0.5;
comboText.scaleY = 0.5;
tween(comboText, {
scaleX: 1.2,
scaleY: 1.2,
alpha: 1
}, {
duration: 200,
easing: tween.easeInOut
});
} else {
// Hide combo text when combo ends
tween(comboText, {
alpha: 0,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 200,
easing: tween.easeOut
});
}
}
function updateUI() {
// Load gold from storage to ensure synchronization
gold = storage.gold || 0;
scoreText.setText('Score: ' + score);
levelText.setText('Level: ' + level);
goldText.setText('Gold: ' + gold);
hourglassText.setText('Hourglass: ' + hourglassCount);
// Save gold to storage
storage.gold = gold;
// Update statistics
if (!storage.highestScore || score > storage.highestScore) {
storage.highestScore = score;
}
if (!storage.highestLevel || level > storage.highestLevel) {
storage.highestLevel = level;
}
if (!storage.totalGoldEarned) {
storage.totalGoldEarned = 0;
}
storage.totalGoldEarned += gold - (storage.lastGold || 0);
storage.lastGold = gold;
// Update progress bar using new level progression system
var currentLevelScore = getRequiredScoreForLevel(level);
var nextLevelScore = getRequiredScoreForLevel(level + 1);
var progress = (score - currentLevelScore) / (nextLevelScore - currentLevelScore);
progress = Math.max(0, Math.min(1, progress)); // Clamp between 0 and 1
// Animate progress bar fill
tween(progressBarFill, {
scaleX: progress
}, {
duration: 200,
easing: tween.easeInOut
});
}
function activateSpecialCandy(candy) {
if (!candy.isSpecial) return;
var row = candy.row;
var col = candy.col;
switch (candy.specialType) {
case 'blueBomb':
// Destroy 3x3 area
for (var r = Math.max(0, row - 1); r <= Math.min(GRID_SIZE - 1, row + 1); r++) {
for (var c = Math.max(0, col - 1); c <= Math.min(GRID_SIZE - 1, col + 1); c++) {
if (grid[r][c] && grid[r][c] !== candy) {
explodeCandyWithScore(grid[r][c]);
grid[r][c] = null;
}
}
}
break;
case 'redRocket':
// Clear entire row and column
for (var c = 0; c < GRID_SIZE; c++) {
if (grid[row][c] && grid[row][c] !== candy) {
explodeCandyWithScore(grid[row][c]);
grid[row][c] = null;
}
}
for (var r = 0; r < GRID_SIZE; r++) {
if (grid[r][col] && grid[r][col] !== candy) {
explodeCandyWithScore(grid[r][col]);
grid[r][col] = null;
}
}
break;
case 'greenPentagon':
// Destroy candies in a plus pattern (5 directions)
var directions = [[-2, 0], [-1, 0], [0, 0], [1, 0], [2, 0],
// Horizontal line
[0, -2], [0, -1], [0, 1], [0, 2] // Vertical line (excluding center)
];
for (var d = 0; d < directions.length; d++) {
var newRow = row + directions[d][0];
var newCol = col + directions[d][1];
if (newRow >= 0 && newRow < GRID_SIZE && newCol >= 0 && newCol < GRID_SIZE) {
if (grid[newRow][newCol] && grid[newRow][newCol] !== candy) {
explodeCandyWithScore(grid[newRow][newCol]);
grid[newRow][newCol] = null;
}
}
}
break;
case 'orangeLollipop':
// Destroy all candies of the same color as adjacent candies
var adjacentColors = [];
var adjacentPositions = [[-1, 0], [1, 0], [0, -1], [0, 1]];
for (var a = 0; a < adjacentPositions.length; a++) {
var adjRow = row + adjacentPositions[a][0];
var adjCol = col + adjacentPositions[a][1];
if (adjRow >= 0 && adjRow < GRID_SIZE && adjCol >= 0 && adjCol < GRID_SIZE) {
if (grid[adjRow][adjCol] && adjacentColors.indexOf(grid[adjRow][adjCol].type) === -1) {
adjacentColors.push(grid[adjRow][adjCol].type);
}
}
}
// Destroy all candies of adjacent colors with staggered timing
var destroyIndex = 0;
for (var r = 0; r < GRID_SIZE; r++) {
for (var c = 0; c < GRID_SIZE; c++) {
if (grid[r][c] && grid[r][c] !== candy && adjacentColors.indexOf(grid[r][c].type) !== -1) {
(function (targetCandy, delay) {
LK.setTimeout(function () {
if (targetCandy.parent) {
tween(targetCandy.graphics, {
tint: 0xFFA500
}, {
duration: 100,
onFinish: function onFinish() {
explodeCandyWithScore(targetCandy);
grid[targetCandy.row][targetCandy.col] = null;
}
});
}
}, delay);
})(grid[r][c], destroyIndex * 30);
destroyIndex++;
}
}
}
break;
case 'purpleBerry':
// Create a wave effect that spreads outward in rings
var maxDistance = 3;
for (var distance = 1; distance <= maxDistance; distance++) {
(function (dist) {
LK.setTimeout(function () {
for (var r = Math.max(0, row - dist); r <= Math.min(GRID_SIZE - 1, row + dist); r++) {
for (var c = Math.max(0, col - dist); c <= Math.min(GRID_SIZE - 1, col + dist); c++) {
// Only destroy candies on the ring edge
var actualDist = Math.max(Math.abs(r - row), Math.abs(c - col));
if (actualDist === dist && grid[r][c] && grid[r][c] !== candy) {
tween(grid[r][c].graphics, {
tint: 0x9013fe,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 150,
onFinish: function onFinish() {
if (grid[r] && grid[r][c]) {
explodeCandyWithScore(grid[r][c]);
grid[r][c] = null;
}
}
});
}
}
}
}, (dist - 1) * 200);
})(distance);
}
break;
case 'discoBall':
// Check if we're combining with purple candy first
var adjacentPurpleCandies = [];
var adjacentPositions = [[-1, 0], [1, 0], [0, -1], [0, 1]];
for (var a = 0; a < adjacentPositions.length; a++) {
var adjRow = row + adjacentPositions[a][0];
var adjCol = col + adjacentPositions[a][1];
if (adjRow >= 0 && adjRow < GRID_SIZE && adjCol >= 0 && adjCol < GRID_SIZE) {
if (grid[adjRow][adjCol] && grid[adjRow][adjCol].type === 'purple' && !grid[adjRow][adjCol].isSpecial) {
adjacentPurpleCandies.push(grid[adjRow][adjCol]);
}
}
}
// Check if we're combining with red rocket first
var adjacentRedRockets = [];
for (var a = 0; a < adjacentPositions.length; a++) {
var adjRow = row + adjacentPositions[a][0];
var adjCol = col + adjacentPositions[a][1];
if (adjRow >= 0 && adjRow < GRID_SIZE && adjCol >= 0 && adjCol < GRID_SIZE) {
if (grid[adjRow][adjCol] && grid[adjRow][adjCol].isSpecial && grid[adjRow][adjCol].specialType === 'redRocket') {
adjacentRedRockets.push(grid[adjRow][adjCol]);
}
}
}
if (adjacentRedRockets.length > 0) {
// Disco ball + red rocket combo: transform all candies to random candy types (no explosions)
var redRocketCandy = adjacentRedRockets[0];
// Remove red rocket without explosion
grid[redRocketCandy.row][redRocketCandy.col] = null;
if (redRocketCandy.parent) {
redRocketCandy.parent.removeChild(redRocketCandy);
}
// Create spectacular combination effect
tween(candy.graphics, {
scaleX: 2.0,
scaleY: 2.0,
tint: 0xFF0000,
rotation: Math.PI * 4
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Transform all candies to random candy types
for (var r = 0; r < GRID_SIZE; r++) {
for (var c = 0; c < GRID_SIZE; c++) {
if (grid[r][c] && grid[r][c] !== candy) {
var targetCandy = grid[r][c];
// Choose random candy type
var randomColor = COLORS[Math.floor(Math.random() * COLORS.length)];
// Transform candy with delay for visual effect
(function (candyToTransform, newColor, delay) {
LK.setTimeout(function () {
if (candyToTransform && candyToTransform.parent) {
// Update candy type
candyToTransform.type = newColor;
// Remove old graphics
candyToTransform.removeChild(candyToTransform.graphics);
// Create new graphics with new color
var assetMap = {
'blue': 'blueCandy',
'red': 'redCandy',
'green': 'greenCandy',
'orange': 'orangeCandy',
'purple': 'purpleCandy'
};
candyToTransform.graphics = candyToTransform.attachAsset(assetMap[newColor], {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
});
// Reset special properties if any
candyToTransform.isSpecial = false;
candyToTransform.specialType = null;
// Add transformation effect
tween(candyToTransform.graphics, {
scaleX: 1.2,
scaleY: 1.2,
tint: 0xFFFFFF
}, {
duration: 300,
easing: tween.bounceOut,
onFinish: function onFinish() {
tween(candyToTransform.graphics, {
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 200,
easing: tween.easeOut
});
}
});
}
}, delay);
})(targetCandy, randomColor, (r + c) * 30);
}
}
}
LK.effects.flashScreen(0xFF0000, 800);
}
});
// Add bonus score for combination
score += 5000;
gold += 2500;
updateUI();
LK.getSound('powerup').play();
break;
}
if (adjacentPurpleCandies.length > 0) {
// Disco ball + purple combo: create white shining vriper
var purpleCandy = adjacentPurpleCandies[0];
// Transform this disco ball into vriper
candy.makeSpecial('vriper');
// Remove purple candy
grid[purpleCandy.row][purpleCandy.col] = null;
purpleCandy.explode();
// Create spectacular combination effect
tween(candy.graphics, {
scaleX: 2.0,
scaleY: 2.0,
tint: 0xFFFFFF,
rotation: Math.PI * 4
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Add continuous white shining effect
var _shineVriper = function shineVriper() {
if (candy && candy.isSpecial && candy.specialType === 'vriper' && candy.parent) {
tween(candy.graphics, {
scaleX: 1.3,
scaleY: 1.3,
tint: 0xFFFFFF,
alpha: 1.0
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(candy.graphics, {
scaleX: 1.1,
scaleY: 1.1,
tint: 0xF0F0F0,
alpha: 0.9
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
LK.setTimeout(_shineVriper, 100);
}
});
}
});
}
};
_shineVriper();
LK.effects.flashScreen(0xFFFFFF, 800);
}
});
// Add bonus score for combination
score += 4000;
gold += 2000;
updateUI();
LK.getSound('powerup').play();
break;
}
// Check if we're combining with another disco ball
var adjacentDiscoBalls = [];
for (var a = 0; a < adjacentPositions.length; a++) {
var adjRow = row + adjacentPositions[a][0];
var adjCol = col + adjacentPositions[a][1];
if (adjRow >= 0 && adjRow < GRID_SIZE && adjCol >= 0 && adjCol < GRID_SIZE) {
if (grid[adjRow][adjCol] && grid[adjRow][adjCol].isSpecial && grid[adjRow][adjCol].specialType === 'discoBall') {
adjacentDiscoBalls.push(grid[adjRow][adjCol]);
}
}
}
if (adjacentDiscoBalls.length > 0) {
// Disco ball + disco ball combo: destroy ALL candies on the grid
// Create massive visual effect
tween(candy.graphics, {
scaleX: 2.0,
scaleY: 2.0,
rotation: Math.PI * 4
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Destroy all candies in waves from center outward
var allCandies = [];
for (var r = 0; r < GRID_SIZE; r++) {
for (var c = 0; c < GRID_SIZE; c++) {
if (grid[r][c] && grid[r][c] !== candy) {
// Calculate distance from center for wave effect
var distance = Math.abs(r - row) + Math.abs(c - col);
allCandies.push({
candy: grid[r][c],
distance: distance
});
}
}
}
// Sort by distance for wave effect
allCandies.sort(function (a, b) {
return a.distance - b.distance;
});
// Clear grid immediately to prevent null reference errors
for (var r = 0; r < GRID_SIZE; r++) {
for (var c = 0; c < GRID_SIZE; c++) {
if (grid[r][c] && grid[r][c] !== candy) {
grid[r][c] = null;
}
}
}
// Destroy all candies with wave timing
for (var i = 0; i < allCandies.length; i++) {
(function (candyData, index) {
LK.setTimeout(function () {
var targetCandy = candyData.candy;
if (targetCandy && targetCandy.parent) {
// Flash the candy bright white before exploding
tween(targetCandy.graphics, {
tint: 0xFFFFFF,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 150,
onFinish: function onFinish() {
explodeCandyWithScore(targetCandy);
}
});
}
}, candyData.distance * 80 + index * 20);
})(allCandies[i], i);
}
// Add screen flash effect when all candies are destroyed
LK.setTimeout(function () {
LK.effects.flashScreen(0xFFFFFF, 500);
// After the flash effect, drop new candies to fill the entire grid
LK.setTimeout(function () {
dropCandies();
LK.setTimeout(function () {
processMatches();
}, 300);
}, 500);
}, allCandies.length * 100 + 500);
}
});
} else {
// Normal disco ball activation
// Create sparkle effect on disco ball before activation
tween(candy.graphics, {
scaleX: 1.2,
scaleY: 1.2,
rotation: Math.PI * 2
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Destroy 13 random candies
var randomCandies = [];
for (var r = 0; r < GRID_SIZE; r++) {
for (var c = 0; c < GRID_SIZE; c++) {
if (grid[r][c] && grid[r][c] !== candy) {
randomCandies.push(grid[r][c]);
}
}
}
// Destroy candies with staggered timing for visual effect
var destroyCount = Math.min(13, randomCandies.length);
for (var i = 0; i < destroyCount; i++) {
(function (index) {
LK.setTimeout(function () {
if (randomCandies.length > 0) {
var randomIndex = Math.floor(Math.random() * randomCandies.length);
var randomCandy = randomCandies[randomIndex];
// Flash the candy white before exploding
tween(randomCandy.graphics, {
tint: 0xFFFFFF
}, {
duration: 100,
onFinish: function onFinish() {
explodeCandyWithScore(randomCandy);
grid[randomCandy.row][randomCandy.col] = null;
}
});
randomCandies.splice(randomIndex, 1);
}
}, index * 50);
})(i);
}
}
});
}
break;
case 'supernova':
// Check if we're combining with disco ball
var adjacentDiscoBalls = [];
var adjacentPositions = [[-1, 0], [1, 0], [0, -1], [0, 1]];
for (var a = 0; a < adjacentPositions.length; a++) {
var adjRow = row + adjacentPositions[a][0];
var adjCol = col + adjacentPositions[a][1];
if (adjRow >= 0 && adjRow < GRID_SIZE && adjCol >= 0 && adjCol < GRID_SIZE) {
if (grid[adjRow][adjCol] && grid[adjRow][adjCol].isSpecial && grid[adjRow][adjCol].specialType === 'discoBall') {
adjacentDiscoBalls.push(grid[adjRow][adjCol]);
}
}
}
if (adjacentDiscoBalls.length > 0) {
// Supernova + Disco Ball combo: create writerpir (they disappear and writerpir appears)
var discoBallCandy = adjacentDiscoBalls[0];
// Transform this supernova into writerpir
candy.makeSpecial('writerpir');
// Remove disco ball
grid[discoBallCandy.row][discoBallCandy.col] = null;
discoBallCandy.explode();
// Create spectacular combination effect
tween(candy.graphics, {
scaleX: 2.5,
scaleY: 2.5,
tint: 0x8B0000,
rotation: Math.PI * 6
}, {
duration: 1500,
easing: tween.easeInOut,
onFinish: function onFinish() {
LK.effects.flashScreen(0x8B0000, 800);
}
});
break;
}
// Normal supernova: massive explosion that destroys everything on the grid in expanding waves
// Create expanding wave effect that destroys the entire grid
var maxWaves = Math.max(GRID_SIZE, GRID_SIZE);
for (var wave = 1; wave <= maxWaves; wave++) {
(function (waveDistance) {
LK.setTimeout(function () {
var candiesInWave = [];
// Collect all candies at this wave distance
for (var r = 0; r < GRID_SIZE; r++) {
for (var c = 0; c < GRID_SIZE; c++) {
var distance = Math.max(Math.abs(r - row), Math.abs(c - col));
if (distance === waveDistance && grid[r][c] && grid[r][c] !== candy) {
candiesInWave.push(grid[r][c]);
grid[r][c] = null; // Remove from grid immediately
}
}
}
// Destroy all candies in this wave with spectacular effect
for (var i = 0; i < candiesInWave.length; i++) {
(function (targetCandy, index) {
if (targetCandy && targetCandy.parent) {
// If the target candy is special, activate it first
if (targetCandy.isSpecial) {
// Create a temporary position for the special candy
var tempRow = targetCandy.row;
var tempCol = targetCandy.col;
// Activate the special candy effect
activateSpecialCandy(targetCandy);
} else {
// Flash bright gold then explode
tween(targetCandy.graphics, {
tint: 0xFFD700,
scaleX: 1.8,
scaleY: 1.8,
alpha: 1.0
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
explodeCandyWithScore(targetCandy);
}
});
}
}
})(candiesInWave[i], i);
}
}, waveDistance * 150); // Stagger waves
})(wave);
}
// Create supernova visual effect
tween(candy.graphics, {
scaleX: 3.0,
scaleY: 3.0,
tint: 0xFFFFFF,
alpha: 0.8,
rotation: Math.PI * 6
}, {
duration: 2000,
easing: tween.easeOut,
onFinish: function onFinish() {
// Massive screen flash when supernova completes
LK.effects.flashScreen(0xFFD700, 1000);
// Give massive bonus for supernova activation
score += 10000;
gold += 5000;
updateUI();
}
});
break;
case 'expires':
// Check if we're combining with purple candy first
var adjacentPurpleCandies = [];
var adjacentPositions = [[-1, 0], [1, 0], [0, -1], [0, 1]];
for (var a = 0; a < adjacentPositions.length; a++) {
var adjRow = row + adjacentPositions[a][0];
var adjCol = col + adjacentPositions[a][1];
if (adjRow >= 0 && adjRow < GRID_SIZE && adjCol >= 0 && adjCol < GRID_SIZE) {
if (grid[adjRow][adjCol] && grid[adjRow][adjCol].type === 'purple' && !grid[adjRow][adjCol].isSpecial) {
adjacentPurpleCandies.push(grid[adjRow][adjCol]);
}
}
}
if (adjacentPurpleCandies.length > 0) {
// Expires + Purple candy combo: create void
var purpleCandy = adjacentPurpleCandies[0];
// Remove purple candy
grid[purpleCandy.row][purpleCandy.col] = null;
purpleCandy.explode();
// Transform expires into void
createVoidAt(candy.row, candy.col);
// Create spectacular combination effect
LK.effects.flashScreen(0x6e00ff, 800);
// Show void creation notification
var voidText = new Text2('ZAMANSIZ KARA DELIK + MOR = VOID!', {
size: 80,
fill: '#6e00ff'
});
voidText.anchor.set(0.5, 0.5);
voidText.x = 1024;
voidText.y = 1366;
voidText.alpha = 0;
game.addChild(voidText);
tween(voidText, {
alpha: 1,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 400,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(voidText, {
alpha: 0
}, {
duration: 400,
onFinish: function onFinish() {
if (voidText.parent) voidText.parent.removeChild(voidText);
}
});
}, 1200);
}
});
// Add bonus score for combination
score += 6000;
gold += 3000;
updateUI();
LK.getSound('powerup').play();
break;
}
// Check if we're combining with black hole
var adjacentBlackHoles = [];
for (var a = 0; a < adjacentPositions.length; a++) {
var adjRow = row + adjacentPositions[a][0];
var adjCol = col + adjacentPositions[a][1];
if (adjRow >= 0 && adjRow < GRID_SIZE && adjCol >= 0 && adjCol < GRID_SIZE) {
if (grid[adjRow][adjCol] && grid[adjRow][adjCol].isSpecial && grid[adjRow][adjCol].specialType === 'blackHole') {
adjacentBlackHoles.push(grid[adjRow][adjCol]);
}
}
}
if (adjacentBlackHoles.length > 0) {
// Expires + Black Hole combo: create writerpir
var blackHoleCandy = adjacentBlackHoles[0];
// Transform this expires into writerpir
candy.makeSpecial('writerpir');
// Remove black hole
grid[blackHoleCandy.row][blackHoleCandy.col] = null;
blackHoleCandy.explode();
// Create spectacular combination effect
tween(candy.graphics, {
scaleX: 2.5,
scaleY: 2.5,
tint: 0x8B0000,
rotation: Math.PI * 6
}, {
duration: 1500,
easing: tween.easeInOut,
onFinish: function onFinish() {
LK.effects.flashScreen(0x8B0000, 800);
}
});
break;
}
// Normal expires: turn all candies into a single random non-special, non-redRocket candy type
// Pick a random color from COLORS, but not 'red' (to avoid redRocket), and not a special
var availableColors = [];
for (var i = 0; i < COLORS.length; i++) {
if (COLORS[i] !== 'red') availableColors.push(COLORS[i]);
}
var randomType = availableColors[Math.floor(Math.random() * availableColors.length)];
var assetMap = {
'blue': 'blueCandy',
'green': 'greenCandy',
'orange': 'orangeCandy',
'purple': 'purpleCandy'
};
for (var r = 0; r < GRID_SIZE; r++) {
for (var c = 0; c < GRID_SIZE; c++) {
if (grid[r][c] && grid[r][c] !== candy) {
var targetCandy = grid[r][c];
// Transform to the chosen randomType with delay
(function (candyToTransform, delay) {
LK.setTimeout(function () {
if (candyToTransform && candyToTransform.parent) {
// Remove old graphics
candyToTransform.removeChild(candyToTransform.graphics);
// Set new type
candyToTransform.type = randomType;
// Attach new graphics
candyToTransform.graphics = candyToTransform.attachAsset(assetMap[randomType], {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
});
// Reset special properties
candyToTransform.isSpecial = false;
candyToTransform.specialType = null;
candyToTransform.isTimeless = false;
// Add transformation effect
tween(candyToTransform.graphics, {
scaleX: 1.2,
scaleY: 1.2,
tint: 0xFFFFFF
}, {
duration: 300,
easing: tween.bounceOut,
onFinish: function onFinish() {
tween(candyToTransform.graphics, {
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 200,
easing: tween.easeOut
});
}
});
}
}, delay);
})(targetCandy, (r + c) * 50);
}
}
}
// Create expires visual effect
tween(candy.graphics, {
scaleX: 2.5,
scaleY: 2.5,
tint: 0xFF4500,
rotation: Math.PI * 4
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
LK.effects.flashScreen(0xFF4500, 500);
score += 8000;
gold += 4000;
updateUI();
}
});
break;
case 'writerpir':
// Writerpir: turn entire map into supernovas when it explodes
for (var r = 0; r < GRID_SIZE; r++) {
for (var c = 0; c < GRID_SIZE; c++) {
if (grid[r][c] && grid[r][c] !== candy) {
var targetCandy = grid[r][c];
// Transform to supernova with spectacular delay
(function (candyToTransform, delay) {
LK.setTimeout(function () {
if (candyToTransform && candyToTransform.parent) {
candyToTransform.makeSpecial('supernova');
// Add supernova creation effect
tween(candyToTransform.graphics, {
scaleX: 1.3,
scaleY: 1.3,
tint: 0xFFD700
}, {
duration: 500,
easing: tween.bounceOut,
onFinish: function onFinish() {
// Add continuous pulsing glow effect
var _pulseSuperNova = function pulseSuperNova() {
if (candyToTransform && candyToTransform.isSpecial && candyToTransform.specialType === 'supernova' && candyToTransform.parent) {
tween(candyToTransform.graphics, {
scaleX: 1.5,
scaleY: 1.5,
tint: 0xFFFF00
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(candyToTransform.graphics, {
scaleX: 1.3,
scaleY: 1.3,
tint: 0xFFD700
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
LK.setTimeout(_pulseSuperNova, 200);
}
});
}
});
}
};
_pulseSuperNova();
}
});
}
}, delay);
})(targetCandy, (r + c) * 80);
}
}
}
// Create writerpir visual effect
tween(candy.graphics, {
scaleX: 3.5,
scaleY: 3.5,
tint: 0x8B0000,
rotation: Math.PI * 8,
alpha: 0.9
}, {
duration: 2000,
easing: tween.easeOut,
onFinish: function onFinish() {
LK.effects.flashScreen(0x8B0000, 1000);
score += 15000;
gold += 8000;
updateUI();
}
});
break;
case 'blackHole':
// Check if we're combining with another black hole
var adjacentBlackHoles = [];
var adjacentPositions = [[-1, 0], [1, 0], [0, -1], [0, 1]];
for (var a = 0; a < adjacentPositions.length; a++) {
var adjRow = row + adjacentPositions[a][0];
var adjCol = col + adjacentPositions[a][1];
if (adjRow >= 0 && adjRow < GRID_SIZE && adjCol >= 0 && adjCol < GRID_SIZE) {
if (grid[adjRow][adjCol] && grid[adjRow][adjCol].isSpecial && grid[adjRow][adjCol].specialType === 'blackHole') {
adjacentBlackHoles.push(grid[adjRow][adjCol]);
}
}
}
if (adjacentBlackHoles.length > 0) {
// Black hole + black hole combo: create supernova
var otherBlackHole = adjacentBlackHoles[0];
// Transform this black hole into supernova
candy.makeSpecial('supernova');
// Remove other black hole
grid[otherBlackHole.row][otherBlackHole.col] = null;
otherBlackHole.explode();
// Create spectacular combination effect
tween(candy.graphics, {
scaleX: 2.5,
scaleY: 2.5,
tint: 0xFFD700,
rotation: Math.PI * 6
}, {
duration: 1500,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Add continuous pulsing glow effect
var _pulseSuperNova = function pulseSuperNova() {
if (candy && candy.isSpecial && candy.specialType === 'supernova' && candy.parent) {
tween(candy.graphics, {
scaleX: 1.5,
scaleY: 1.5,
tint: 0xFFFF00
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(candy.graphics, {
scaleX: 1.3,
scaleY: 1.3,
tint: 0xFFFFFF
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
LK.setTimeout(_pulseSuperNova, 200);
}
});
}
});
}
};
_pulseSuperNova();
LK.effects.flashScreen(0xFFD700, 800);
}
});
break;
}
// Normal black hole: compress all candies in 8-range area into one square and explode
var blackHoleRange = 4; // 8-range means 4 cells in each direction (9x9 area total)
var candiesInRange = [];
// Collect all candies within 8-range (4 cells in each direction)
for (var r = Math.max(0, row - blackHoleRange); r <= Math.min(GRID_SIZE - 1, row + blackHoleRange); r++) {
for (var c = Math.max(0, col - blackHoleRange); c <= Math.min(GRID_SIZE - 1, col + blackHoleRange); c++) {
if (grid[r][c] && grid[r][c] !== candy) {
candiesInRange.push(grid[r][c]);
grid[r][c] = null; // Remove from grid immediately
}
}
}
// Create compression effect - move all candies to black hole center
for (var i = 0; i < candiesInRange.length; i++) {
(function (targetCandy, index) {
// Validate candy still exists before animating
if (targetCandy && targetCandy.parent) {
// Animate candy moving to black hole center
tween(targetCandy, {
x: candy.x,
y: candy.y,
scaleX: 0.1,
scaleY: 0.1,
alpha: 0.5
}, {
duration: 800 + index * 20,
// Staggered timing
easing: tween.easeIn,
onFinish: function onFinish() {
// Check if candy still exists before processing
if (targetCandy && targetCandy.parent) {
// Check if the pulled candy is special and activate it first
if (targetCandy.isSpecial) {
// Create a temporary grid position for the special candy at black hole center
var tempRow = row;
var tempCol = col;
targetCandy.row = tempRow;
targetCandy.col = tempCol;
// Activate the special candy effect
activateSpecialCandy(targetCandy);
} else {
// Explode candy with score when it reaches center
explodeCandyWithScore(targetCandy);
}
}
}
});
}
})(candiesInRange[i], i);
}
// Create visual black hole effect
tween(candy.graphics, {
scaleX: 2.0,
scaleY: 2.0,
rotation: Math.PI * 4,
alpha: 0.3
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Flash effect when compression is complete
LK.effects.flashScreen(0x000000, 300);
}
});
break;
case 'converter':
// Converter: check for adjacent candies to combine with
var adjacentPositions = [[-1, 0], [1, 0], [0, -1], [0, 1]];
var adjacentCandies = [];
for (var a = 0; a < adjacentPositions.length; a++) {
var adjRow = row + adjacentPositions[a][0];
var adjCol = col + adjacentPositions[a][1];
if (adjRow >= 0 && adjRow < GRID_SIZE && adjCol >= 0 && adjCol < GRID_SIZE) {
if (grid[adjRow][adjCol] && !grid[adjRow][adjCol].isSpecial) {
adjacentCandies.push(grid[adjRow][adjCol]);
}
}
}
if (adjacentCandies.length > 0) {
// Combine with first adjacent candy
var targetCandy = adjacentCandies[0];
var targetColor = targetCandy.type;
// Remove the target candy
grid[targetCandy.row][targetCandy.col] = null;
targetCandy.explode();
// Create the appropriate special candy based on target color
var newSpecialType;
if (targetColor === 'blue') {
newSpecialType = 'blueBomb';
} else if (targetColor === 'red') {
newSpecialType = 'redRocket';
} else if (targetColor === 'green') {
newSpecialType = 'greenPentagon';
} else if (targetColor === 'orange') {
newSpecialType = 'orangeLollipop';
} else if (targetColor === 'purple') {
newSpecialType = 'blackHole';
}
// Transform converter into the new special candy
candy.makeSpecial(newSpecialType);
// Set flag to prevent immediate activation
candy.justCreated = true;
// Create spectacular combination effect
tween(candy.graphics, {
scaleX: 2.0,
scaleY: 2.0,
tint: 0x4a90e2,
rotation: Math.PI * 2
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Flash effect to show transformation
LK.effects.flashScreen(0x4a90e2, 500);
// Add bonus score for converter combination
score += 3000;
gold += 1500;
updateUI();
LK.getSound('powerup').play();
// Remove the creation flag after animation completes
LK.setTimeout(function () {
if (candy && candy.parent) {
candy.justCreated = false;
}
}, 1000);
}
});
// Don't break here - return early to prevent converter destruction
return;
}
// No adjacent candies - converter just explodes without effect
tween(candy.graphics, {
scaleX: 1.5,
scaleY: 1.5,
tint: 0x4a90e2,
alpha: 0.5
}, {
duration: 500,
easing: tween.easeOut
});
break;
case 'vriper':
// First check for vriper + vriper combination
var adjacentVripers = [];
var adjacentPositions = [[-1, 0], [1, 0], [0, -1], [0, 1]];
for (var a = 0; a < adjacentPositions.length; a++) {
var adjRow = row + adjacentPositions[a][0];
var adjCol = col + adjacentPositions[a][1];
if (adjRow >= 0 && adjRow < GRID_SIZE && adjCol >= 0 && adjCol < GRID_SIZE) {
if (grid[adjRow][adjCol] && grid[adjRow][adjCol].isSpecial && grid[adjRow][adjCol].specialType === 'vriper') {
adjacentVripers.push(grid[adjRow][adjCol]);
}
}
}
if (adjacentVripers.length > 0) {
// Vriper + vriper combo: both disappear and create disco ball
var otherVriper = adjacentVripers[0];
// Transform this vriper into disco ball
candy.makeSpecial('discoBall');
// Remove other vriper
grid[otherVriper.row][otherVriper.col] = null;
otherVriper.explode();
// Create spectacular combination effect
tween(candy.graphics, {
scaleX: 2.0,
scaleY: 2.0,
tint: 0xFFFFFF,
rotation: Math.PI * 4
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Add continuous rotation to disco ball
var _rotateDiscoBall = function rotateDiscoBall() {
if (candy.isSpecial && candy.specialType === 'discoBall' && candy.parent) {
tween(candy.graphics, {
rotation: candy.graphics.rotation + Math.PI * 2
}, {
duration: 6000,
easing: tween.linear,
onFinish: function onFinish() {
LK.setTimeout(_rotateDiscoBall, 100);
}
});
}
};
_rotateDiscoBall();
LK.effects.flashScreen(0xFFFFFF, 800);
}
});
// Add bonus score for combination
score += 6000;
gold += 3000;
updateUI();
LK.getSound('powerup').play();
break;
}
// Vriper: can combine with any color candy to destroy all candies of that color
// Check adjacent positions for any candy (not special)
var adjacentCandies = [];
for (var a = 0; a < adjacentPositions.length; a++) {
var adjRow = row + adjacentPositions[a][0];
var adjCol = col + adjacentPositions[a][1];
if (adjRow >= 0 && adjRow < GRID_SIZE && adjCol >= 0 && adjCol < GRID_SIZE) {
if (grid[adjRow][adjCol] && !grid[adjRow][adjCol].isSpecial) {
adjacentCandies.push(grid[adjRow][adjCol]);
}
}
}
if (adjacentCandies.length > 0) {
// Combine with first adjacent candy
var targetCandy = adjacentCandies[0];
var targetColor = targetCandy.type;
// Create white circle effect that expands
tween(candy.graphics, {
scaleX: 4.0,
scaleY: 4.0,
alpha: 0.3,
tint: 0xFFFFFF
}, {
duration: 1500,
easing: tween.easeOut,
onFinish: function onFinish() {
// After white circle expansion, destroy all candies of target color
var candiesOfTargetColor = [];
for (var r = 0; r < GRID_SIZE; r++) {
for (var c = 0; c < GRID_SIZE; c++) {
if (grid[r][c] && grid[r][c].type === targetColor && grid[r][c] !== candy) {
candiesOfTargetColor.push(grid[r][c]);
grid[r][c] = null;
}
}
}
// Destroy all candies of target color with white flash effect
for (var i = 0; i < candiesOfTargetColor.length; i++) {
(function (candyToDestroy, index) {
LK.setTimeout(function () {
if (candyToDestroy && candyToDestroy.parent) {
// Flash white before exploding
tween(candyToDestroy.graphics, {
tint: 0xFFFFFF,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 200,
onFinish: function onFinish() {
explodeCandyWithScore(candyToDestroy);
}
});
}
}, index * 50);
})(candiesOfTargetColor[i], i);
}
// Create disco ball at vriper position when vriper + candy combination is complete
LK.setTimeout(function () {
if (candy && candy.parent) {
candy.makeSpecial('discoBall');
// Add creation sparkle effect
tween(candy.graphics, {
scaleX: 1.0,
scaleY: 1.0,
rotation: Math.PI,
tint: 0xFFFFFF
}, {
duration: 300,
easing: tween.bounceOut
});
}
}, candiesOfTargetColor.length * 50 + 500);
}
});
// Add massive bonus for vriper activation
score += 8000;
gold += 4000;
updateUI();
LK.effects.flashScreen(0xFFFFFF, 1000);
LK.getSound('powerup').play();
break;
}
// Normal vriper without adjacent candies - just shine
tween(candy.graphics, {
scaleX: 2.0,
scaleY: 2.0,
tint: 0xFFFFFF,
alpha: 0.8
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(candy.graphics, {
scaleX: 1.1,
scaleY: 1.1,
alpha: 1.0
}, {
duration: 500,
easing: tween.easeOut
});
}
});
break;
case 'hourglass':
// Check if we're combining with another candy first
var adjacentCandies = [];
var adjacentPositions = [[-1, 0], [1, 0], [0, -1], [0, 1]];
for (var a = 0; a < adjacentPositions.length; a++) {
var adjRow = row + adjacentPositions[a][0];
var adjCol = col + adjacentPositions[a][1];
if (adjRow >= 0 && adjRow < GRID_SIZE && adjCol >= 0 && adjCol < GRID_SIZE) {
if (grid[adjRow][adjCol] && !grid[adjRow][adjCol].isSpecial) {
adjacentCandies.push(grid[adjRow][adjCol]);
}
}
}
if (adjacentCandies.length > 0) {
// Hourglass combining with adjacent candy - cover all map with a random candy type
var targetCandy = adjacentCandies[0];
// Remove the adjacent candy
grid[targetCandy.row][targetCandy.col] = null;
targetCandy.explode();
// Create spectacular combination effect
tween(candy.graphics, {
scaleX: 3.0,
scaleY: 3.0,
tint: 0xFFD700,
rotation: Math.PI * 6
}, {
duration: 1500,
easing: tween.easeOut,
onFinish: function onFinish() {
LK.effects.flashScreen(0xFFD700, 1200);
}
});
} else {
// Normal hourglass activation
// Create hourglass visual effect
tween(candy.graphics, {
scaleX: 2.5,
scaleY: 2.5,
tint: 0xFFD700,
rotation: Math.PI * 4
}, {
duration: 1200,
easing: tween.easeOut,
onFinish: function onFinish() {
LK.effects.flashScreen(0xFFD700, 800);
}
});
}
// Hourglass: turn all candies on the map to a single random candy type with wave effect
var centerRow = candy.row;
var centerCol = candy.col;
var maxDistance = Math.max(GRID_SIZE, GRID_SIZE);
// Pick a random color for the whole map (from COLORS)
var randomColorForMap = COLORS[Math.floor(Math.random() * COLORS.length)];
var assetMap = {
'blue': 'blueCandy',
'red': 'redCandy',
'green': 'greenCandy',
'orange': 'orangeCandy',
'purple': 'purpleCandy'
};
for (var distance = 1; distance <= maxDistance; distance++) {
(function (dist) {
LK.setTimeout(function () {
// Collect all candies at this distance
var candiesAtDistance = [];
for (var r = 0; r < GRID_SIZE; r++) {
for (var c = 0; c < GRID_SIZE; c++) {
var actualDist = Math.max(Math.abs(r - centerRow), Math.abs(c - centerCol));
if (actualDist === dist && grid[r][c] && grid[r][c] !== candy) {
candiesAtDistance.push(grid[r][c]);
}
}
}
// Transform all candies at this distance to the random color
for (var i = 0; i < candiesAtDistance.length; i++) {
(function (targetCandy, index) {
if (targetCandy && targetCandy.parent) {
// Update candy type to the random color
targetCandy.type = randomColorForMap;
// Remove old graphics
targetCandy.removeChild(targetCandy.graphics);
// Create new graphics for the random color
targetCandy.graphics = targetCandy.attachAsset(assetMap[randomColorForMap], {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
});
// Reset special properties
targetCandy.isSpecial = false;
targetCandy.specialType = null;
targetCandy.isTimeless = false;
// Add transformation effect
tween(targetCandy.graphics, {
scaleX: 1.3,
scaleY: 1.3,
tint: 0xFFD700
}, {
duration: 400,
easing: tween.bounceOut,
onFinish: function onFinish() {
tween(targetCandy.graphics, {
scaleX: 0.8,
scaleY: 0.8,
tint: 0xFFFFFF
}, {
duration: 300,
easing: tween.easeOut
});
}
});
}
})(candiesAtDistance[i], i);
}
}, dist * 100); // Stagger waves outward
})(distance);
}
// Add bonus for hourglass activation
score += 8000;
gold += 4000;
updateUI();
LK.getSound('powerup').play();
break;
}
candy.explode();
grid[row][col] = null;
updateUI(); // Update UI to show earned points
LK.getSound('powerup').play();
// Drop candies to fill empty spaces after special candy activation
LK.setTimeout(function () {
dropCandies();
LK.setTimeout(function () {
processMatches();
}, 300);
}, 400);
}
// Variables for swipe detection
var dragStartX = 0;
var dragStartY = 0;
var dragCandy = null;
var isDragging = false;
var SWIPE_THRESHOLD = 80; // Minimum distance for swipe
game.down = function (x, y, obj) {
// Handle name input if active
if (game.nameInputHandler) {
game.nameInputHandler(x, y);
return;
}
// Block all input when game is won
if (gameState === 'victory') {
return; // No input allowed after victory
}
// Handle menu navigation first
if (gameState === 'menu') {
// Check start button click
var dx = x - mainMenuContainer.startButton.x;
var dy = y - mainMenuContainer.startButton.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 200) {
// Animate button press
tween(mainMenuContainer.startButton, {
scaleX: 1.8,
scaleY: 1.3
}, {
duration: 100,
onFinish: function onFinish() {
tween(mainMenuContainer.startButton, {
scaleX: 2.0,
scaleY: 1.5
}, {
duration: 100,
onFinish: function onFinish() {
startGame();
}
});
}
});
return;
}
// Check settings button click
dx = x - mainMenuContainer.settingsButton.x;
dy = y - mainMenuContainer.settingsButton.y;
distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 200) {
// Animate button press
tween(mainMenuContainer.settingsButton, {
scaleX: 1.8,
scaleY: 1.3
}, {
duration: 100,
onFinish: function onFinish() {
tween(mainMenuContainer.settingsButton, {
scaleX: 2.0,
scaleY: 1.5
}, {
duration: 100,
onFinish: function onFinish() {
showSettingsMenu();
}
});
}
});
return;
}
// Check statistics button click
dx = x - mainMenuContainer.statisticsButton.x;
dy = y - mainMenuContainer.statisticsButton.y;
distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 200) {
// Animate button press
tween(mainMenuContainer.statisticsButton, {
scaleX: 1.8,
scaleY: 1.3
}, {
duration: 100,
onFinish: function onFinish() {
tween(mainMenuContainer.statisticsButton, {
scaleX: 2.0,
scaleY: 1.5
}, {
duration: 100,
onFinish: function onFinish() {
showStatisticsMenu();
}
});
}
});
return;
}
// Check new game button click
dx = x - mainMenuContainer.newGameButton.x;
dy = y - mainMenuContainer.newGameButton.y;
distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 200) {
// Animate button press
tween(mainMenuContainer.newGameButton, {
scaleX: 1.8,
scaleY: 1.3
}, {
duration: 100,
onFinish: function onFinish() {
tween(mainMenuContainer.newGameButton, {
scaleX: 2.0,
scaleY: 1.5
}, {
duration: 100,
onFinish: function onFinish() {
// Reset current score and level when starting new game
score = 0;
level = 1;
// Start the game
startGame();
}
});
}
});
return;
}
// Check saves button click
dx = x - mainMenuContainer.savesButton.x;
dy = y - mainMenuContainer.savesButton.y;
distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 200) {
// Animate button press
tween(mainMenuContainer.savesButton, {
scaleX: 1.8,
scaleY: 1.3
}, {
duration: 100,
onFinish: function onFinish() {
tween(mainMenuContainer.savesButton, {
scaleX: 2.0,
scaleY: 1.5
}, {
duration: 100,
onFinish: function onFinish() {
showSavesMenu();
}
});
}
});
return;
}
return; // Don't process game clicks in menu state
}
if (gameState === 'settings') {
// Check back button click
var dx = x - settingsMenuContainer.backButton.x;
var dy = y - settingsMenuContainer.backButton.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 150) {
// Animate button press
tween(settingsMenuContainer.backButton, {
scaleX: 1.3,
scaleY: 1.0
}, {
duration: 100,
onFinish: function onFinish() {
tween(settingsMenuContainer.backButton, {
scaleX: 1.5,
scaleY: 1.2
}, {
duration: 100,
onFinish: function onFinish() {
showMainMenu();
}
});
}
});
return;
}
return; // Don't process game clicks in settings state
}
if (gameState === 'statistics') {
// Check back button click
var dx = x - statisticsMenuContainer.backButton.x;
var dy = y - statisticsMenuContainer.backButton.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 150) {
// Animate button press
tween(statisticsMenuContainer.backButton, {
scaleX: 1.3,
scaleY: 1.0
}, {
duration: 100,
onFinish: function onFinish() {
tween(statisticsMenuContainer.backButton, {
scaleX: 1.5,
scaleY: 1.2
}, {
duration: 100,
onFinish: function onFinish() {
showMainMenu();
}
});
}
});
return;
}
return; // Don't process game clicks in statistics state
}
if (gameState === 'saves') {
// Check back button click
var dx = x - savesMenuContainer.backButton.x;
var dy = y - savesMenuContainer.backButton.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 150) {
// Animate button press
tween(savesMenuContainer.backButton, {
scaleX: 1.3,
scaleY: 1.0
}, {
duration: 100,
onFinish: function onFinish() {
tween(savesMenuContainer.backButton, {
scaleX: 1.5,
scaleY: 1.2
}, {
duration: 100,
onFinish: function onFinish() {
showMainMenu();
}
});
}
});
return;
}
// Check save slot clicks
for (var i = 0; i < savesMenuContainer.saveSlots.length; i++) {
var slot = savesMenuContainer.saveSlots[i];
var dx = x - slot.x;
var dy = y - slot.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 150) {
// Animate slot press
tween(slot.background, {
scaleX: 1.6,
scaleY: 2.3
}, {
duration: 100,
onFinish: function onFinish() {
tween(slot.background, {
scaleX: 1.8,
scaleY: 2.5
}, {
duration: 100,
onFinish: function onFinish() {
// Handle based on saves menu mode
if (savesMenuMode === 'save') {
// Save current score to selected slot
saveGameToSlot(slot.slotIndex);
} else if (savesMenuMode === 'load') {
// Load game from selected slot
loadGameFromSlot(slot.slotIndex);
}
}
});
}
});
return;
}
}
return; // Don't process game clicks in saves state
}
// Only process game clicks when in playing state
if (gameState !== 'playing') return;
// Check for save button click
var dx = x - saveButton.x;
var dy = y - saveButton.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 150) {
// Animate button press
tween(saveButton, {
scaleX: 0.8,
scaleY: 0.5
}, {
duration: 100,
onFinish: function onFinish() {
tween(saveButton, {
scaleX: 1.0,
scaleY: 0.6
}, {
duration: 100,
onFinish: function onFinish() {
// Save game state using individual storage properties
storage.savedScore = score;
storage.savedLevel = level;
storage.savedGold = gold;
storage.savedInventory = inventory;
storage.savedHourglassCount = hourglassCount;
storage.savedComboCount = savedComboCount;
storage.savedYellowCandiesClicked = yellowCandiesClicked;
storage.savedTimestamp = Date.now();
gameStateSaved = true;
// Show save confirmation
var savedText = new Text2('Game Saved!', {
size: 60,
fill: '#00FF00'
});
savedText.anchor.set(0.5, 0.5);
savedText.x = 1024;
savedText.y = 2500;
savedText.alpha = 0;
game.addChild(savedText);
tween(savedText, {
alpha: 1
}, {
duration: 500,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(savedText, {
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
if (savedText.parent) {
savedText.parent.removeChild(savedText);
}
}
});
}, 2000);
}
});
}
});
}
});
return;
}
if (isProcessing) return;
// Reset cascade combo when user makes a new move
cascadeComboCount = 0;
lastCascadeTime = 0;
// Check for shooting star click first (secret feature)
for (var i = 0; i < starField.children.length; i++) {
var child = starField.children[i];
if (child instanceof ShootingStar) {
// Check if click is near the shooting star
var dx = x - child.x;
var dy = y - child.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 50) {
// 50px hit radius
// Activate Hidden Stars achievement tracking if not already achieved
if (!achievements.hiddenStars && !hiddenStarsActivated) {
hiddenStarsActivated = true;
hiddenStarsSequence = [];
return;
}
if (!secretMode) {
activateSecretMode();
} else {
// Return to beginning of game if already in secret mode
restartGame();
}
return;
}
}
}
// Handle secret mode ball clicks
if (secretMode) {
for (var i = 0; i < secretBalls.length; i++) {
var ball = secretBalls[i];
var dx = x - ball.x;
var dy = y - ball.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 100) {
// Ball hit radius
handleSecretBallClick(i);
return;
}
}
return; // Don't handle normal candy clicks in secret mode
}
// Handle Hidden Stars achievement sequence tracking
if (hiddenStarsActivated && !achievements.hiddenStars) {
// Check if any of the numbered balls (1-4) are clicked by checking proximity to their positions
var ballPositions = [{
x: 512,
y: 683,
number: 1
},
// Ball 1
{
x: 1536,
y: 683,
number: 2
},
// Ball 2
{
x: 512,
y: 2049,
number: 3
},
// Ball 3
{
x: 1536,
y: 2049,
number: 4
} // Ball 4
];
for (var i = 0; i < ballPositions.length; i++) {
var pos = ballPositions[i];
var dx = x - pos.x;
var dy = y - pos.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 150) {
// Hit radius for sequence tracking
hiddenStarsSequence.push(pos.number);
// Visual feedback
var feedbackText = new Text2(pos.number.toString(), {
size: 80,
fill: '#FFD700'
});
feedbackText.anchor.set(0.5, 0.5);
feedbackText.x = pos.x;
feedbackText.y = pos.y - 200;
feedbackText.alpha = 0;
game.addChild(feedbackText);
tween(feedbackText, {
alpha: 1,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 300,
onFinish: function onFinish() {
tween(feedbackText, {
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
if (feedbackText.parent) {
feedbackText.parent.removeChild(feedbackText);
}
}
});
}
});
// Check achievement after each number
checkHiddenStarsAchievement();
// Reset sequence if it gets too long or wrong
if (hiddenStarsSequence.length > 4 || hiddenStarsSequence.length === 4 && !achievements.hiddenStars) {
if (!achievements.hiddenStars) {
hiddenStarsSequence = [];
}
}
return;
}
}
}
// Handle candy selection
var candy = getCandyAt(x, y);
if (!candy) {
// Clear selection if clicking empty space
if (selectedCandy) {
selectedCandy.graphics.tint = 0xFFFFFF;
tween(selectedCandy, {
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 100
});
selectedCandy = null;
}
if (selectedEternalCandy) {
selectedEternalCandy.graphics.tint = 0xFFD700;
tween(selectedEternalCandy, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 100
});
selectedEternalCandy = null;
}
return;
}
// Check for double-click to use hourglass and create timeless Karadeniz
var currentTime = Date.now();
var isDoubleClick = currentTime - lastClickTime < DOUBLE_CLICK_THRESHOLD && lastClickedCandy === candy;
if (isDoubleClick && hourglassCount > 0 && candy && !candy.isSpecial) {
// Use hourglass to create timeless Karadeniz
hourglassCount--;
// Transform candy into timeless Karadeniz
candy.makeSpecial('expires');
candy.isTimeless = true;
candy.timelessHealth = 40; // Starts with 40 health
candy.maxTimelessHealth = 40;
// Add to timeless tracking array
timelessKaradenizCandies.push(candy);
// Create transformation effect
tween(candy.graphics, {
scaleX: 1.5,
scaleY: 1.5,
tint: 0xFF4500,
rotation: Math.PI * 2
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
// Start cracking effect animation
startCrackingEffect(candy);
}
});
// Show timeless creation notification
var timelessNotification = new Text2('TIMELESS KARADENIZ CREATED!', {
size: 70,
fill: '#FF4500'
});
timelessNotification.anchor.set(0.5, 0.5);
timelessNotification.x = 1024;
timelessNotification.y = 1200;
timelessNotification.alpha = 0;
game.addChild(timelessNotification);
tween(timelessNotification, {
alpha: 1,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 500,
easing: tween.bounceOut,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(timelessNotification, {
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
if (timelessNotification.parent) {
timelessNotification.parent.removeChild(timelessNotification);
}
}
});
}, 2500);
}
});
updateUI();
LK.getSound('powerup').play();
// Reset click tracking
lastClickTime = 0;
lastClickedCandy = null;
return;
}
// Black hole click tracking for void creation
if (candy && candy.isSpecial && candy.specialType === 'blackHole') {
var key = getGridKey(candy.row, candy.col);
if (!blackHoleClickCounts[key]) blackHoleClickCounts[key] = 0;
blackHoleClickCounts[key]++;
// Visual feedback for click count
var clickText = new Text2(blackHoleClickCounts[key] + '/3', {
size: 60,
fill: '#6e00ff'
});
clickText.anchor.set(0.5, 0.5);
clickText.x = candy.x;
clickText.y = candy.y - 120;
clickText.alpha = 0;
game.addChild(clickText);
tween(clickText, {
alpha: 1,
scaleX: 1.3,
scaleY: 1.3,
y: candy.y - 150
}, {
duration: 200,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(clickText, {
alpha: 0,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 200,
onFinish: function onFinish() {
if (clickText.parent) clickText.parent.removeChild(clickText);
}
});
}, 600);
}
});
// On 3rd click, create void and remove 2 hourglasses
if (blackHoleClickCounts[key] === 3) {
if (hourglassCount >= 2) {
hourglassCount -= 2;
// Remove black hole and create void
if (candy.parent) candy.parent.removeChild(candy);
grid[candy.row][candy.col] = null;
createVoidAt(candy.row, candy.col);
// Show void creation notification
var voidText = new Text2('VOID CREATED!', {
size: 80,
fill: '#6e00ff'
});
voidText.anchor.set(0.5, 0.5);
voidText.x = 1024;
voidText.y = 1366;
voidText.alpha = 0;
game.addChild(voidText);
tween(voidText, {
alpha: 1,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 400,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(voidText, {
alpha: 0
}, {
duration: 400,
onFinish: function onFinish() {
if (voidText.parent) voidText.parent.removeChild(voidText);
}
});
}, 1200);
}
});
updateUI();
} else {
// Not enough hourglasses
var warnText = new Text2('Need 2 Hourglasses!', {
size: 60,
fill: '#FF0000'
});
warnText.anchor.set(0.5, 0.5);
warnText.x = 1024;
warnText.y = 1366;
warnText.alpha = 0;
game.addChild(warnText);
tween(warnText, {
alpha: 1
}, {
duration: 300,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(warnText, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
if (warnText.parent) warnText.parent.removeChild(warnText);
}
});
}, 1000);
}
});
}
blackHoleClickCounts[key] = 0;
return;
}
// On 5th click, transform into void directly
if (blackHoleClickCounts[key] === 5) {
// Transform black hole into void directly
candy.makeSpecial('void');
candy.specialType = 'void';
candy.type = 'void';
candy.voidComboType = null;
candy.voidComboActive = false;
// Replace graphics with void look
candy.removeChild(candy.graphics);
candy.graphics = candy.attachAsset('purpleCandy', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
});
tween(candy.graphics, {
tint: 0x6e00ff,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 400,
onFinish: function onFinish() {
tween(candy.graphics, {
tint: 0x9013fe,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 300
});
}
});
// Add to void positions tracking
voidPositions.push({
row: candy.row,
col: candy.col
});
// Show void transformation notification
var voidText = new Text2('BLACK HOLE → VOID!', {
size: 80,
fill: '#6e00ff'
});
voidText.anchor.set(0.5, 0.5);
voidText.x = 1024;
voidText.y = 1366;
voidText.alpha = 0;
game.addChild(voidText);
tween(voidText, {
alpha: 1,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 400,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(voidText, {
alpha: 0
}, {
duration: 400,
onFinish: function onFinish() {
if (voidText.parent) voidText.parent.removeChild(voidText);
}
});
}, 1200);
}
});
blackHoleClickCounts[key] = 0;
return;
}
// On 7th click, transform void into infinite void
if (blackHoleClickCounts[key] === 7) {
// Transform void into infinite void
candy.isInfiniteVoid = true;
candy.specialType = 'infiniteVoid';
// Enhanced visual effects for infinite void
candy.removeChild(candy.graphics);
candy.graphics = candy.attachAsset('purpleCandy', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
});
tween(candy.graphics, {
tint: 0x4B0082,
scaleX: 1.5,
scaleY: 1.5,
rotation: Math.PI * 2
}, {
duration: 600,
onFinish: function onFinish() {
// Add continuous swirling effect for infinite void
var _swirl = function swirl() {
if (candy && candy.isInfiniteVoid && candy.parent) {
tween(candy.graphics, {
tint: 0x8A2BE2,
scaleX: 1.7,
scaleY: 1.7,
rotation: candy.graphics.rotation + Math.PI * 2
}, {
duration: 1500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(candy.graphics, {
tint: 0x4B0082,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 1500,
easing: tween.easeInOut,
onFinish: function onFinish() {
LK.setTimeout(_swirl, 100);
}
});
}
});
}
};
_swirl();
}
});
// Show infinite void transformation notification
var infiniteVoidText = new Text2('SONSUZ BOŞLUK!', {
size: 90,
fill: '#8A2BE2'
});
infiniteVoidText.anchor.set(0.5, 0.5);
infiniteVoidText.x = 1024;
infiniteVoidText.y = 1366;
infiniteVoidText.alpha = 0;
game.addChild(infiniteVoidText);
tween(infiniteVoidText, {
alpha: 1,
scaleX: 1.4,
scaleY: 1.4,
rotation: 0.1
}, {
duration: 600,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(infiniteVoidText, {
alpha: 0
}, {
duration: 600,
onFinish: function onFinish() {
if (infiniteVoidText.parent) infiniteVoidText.parent.removeChild(infiniteVoidText);
}
});
}, 1500);
}
});
LK.effects.flashScreen(0x8A2BE2, 1000);
blackHoleClickCounts[key] = 0;
return;
}
}
// Update click tracking for double-click detection
lastClickTime = currentTime;
lastClickedCandy = candy;
// Check if clicking on yellow candy for hourglass system (orange candies)
if (candy && candy.type === 'orange') {
// Create unique identifier for this candy position
var candyId = candy.row + '_' + candy.col + '_' + candy.type;
// Check if this yellow candy hasn't been clicked yet
var alreadyClicked = false;
for (var i = 0; i < yellowCandiesClicked.length; i++) {
if (yellowCandiesClicked[i] === candyId) {
alreadyClicked = true;
break;
}
}
// If candy hasn't been clicked yet, mark it as clicked
if (!alreadyClicked) {
yellowCandiesClicked.push(candyId);
// Check if we have 4 yellow candies clicked to create hourglass
if (yellowCandiesClicked.length >= 4) {
// Create hourglass
hourglassCount++;
// Reset yellow candies counter
yellowCandiesClicked = [];
// Save combo count for later use
savedComboCount = cascadeComboCount;
// Show hourglass creation notification
var hourglassNotification = new Text2('HOURGLASS CREATED!', {
size: 80,
fill: '#FFD700'
});
hourglassNotification.anchor.set(0.5, 0.5);
hourglassNotification.x = 1024;
hourglassNotification.y = 1200;
hourglassNotification.alpha = 0;
game.addChild(hourglassNotification);
tween(hourglassNotification, {
alpha: 1,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 500,
easing: tween.bounceOut,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(hourglassNotification, {
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
if (hourglassNotification.parent) {
hourglassNotification.parent.removeChild(hourglassNotification);
}
}
});
}, 2000);
}
});
updateUI();
LK.getSound('powerup').play();
}
}
}
// Check if clicking on a ball (any candy) for Small Collector achievement
if (candy && !achievements.smallCollector) {
// Count total balls on first click if not already set
if (totalBallsToClick === 0) {
for (var row = 0; row < GRID_SIZE; row++) {
for (var col = 0; col < GRID_SIZE; col++) {
if (grid[row][col]) {
totalBallsToClick++;
}
}
}
}
// Create unique identifier for this ball position
var ballId = candy.row + '_' + candy.col;
// Check if this ball hasn't been clicked small yet
var alreadyClickedSmall = false;
for (var i = 0; i < ballsClickedSmall.length; i++) {
if (ballsClickedSmall[i] === ballId) {
alreadyClickedSmall = true;
break;
}
}
// If ball hasn't been clicked small yet, mark it as clicked small
if (!alreadyClickedSmall) {
ballsClickedSmall.push(ballId);
// Check if achievement should be unlocked
checkSmallCollectorAchievement();
}
}
// Add shrinking animation when candy is clicked
tween(candy, {
scaleX: 0.6,
scaleY: 0.6
}, {
duration: 150,
easing: tween.easeIn,
onFinish: function onFinish() {
tween(candy, {
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 150,
easing: tween.bounceOut
});
}
});
// Handle eternal candy clicks first
if (isEternalCandy(candy)) {
if (selectedEternalCandy === null) {
// Select eternal candy
selectedEternalCandy = candy;
candy.graphics.tint = 0xFFFFFF;
tween(candy, {
scaleX: 1.6,
scaleY: 1.6
}, {
duration: 150
});
// Show instruction text
var instructionText = new Text2('Herhangi bir şekere tıklayın!', {
size: 60,
fill: '#FFD700'
});
instructionText.anchor.set(0.5, 0.5);
instructionText.x = 1024;
instructionText.y = 1100;
instructionText.alpha = 0;
game.addChild(instructionText);
tween(instructionText, {
alpha: 1
}, {
duration: 300,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(instructionText, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
if (instructionText.parent) instructionText.parent.removeChild(instructionText);
}
});
}, 2000);
}
});
return;
} else if (selectedEternalCandy === candy) {
// Deselect eternal candy
selectedEternalCandy.graphics.tint = 0xFFD700;
tween(selectedEternalCandy, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 100
});
selectedEternalCandy = null;
return;
}
}
// If eternal candy is selected and we click another candy, teleport eternal candy there
if (selectedEternalCandy && candy !== selectedEternalCandy) {
// Store old position
var oldRow = selectedEternalCandy.row;
var oldCol = selectedEternalCandy.col;
var newRow = candy.row;
var newCol = candy.col;
// Remove candy at target position
if (candy.parent) {
candy.parent.removeChild(candy);
}
grid[newRow][newCol] = null;
// Remove eternal candy from old position
grid[oldRow][oldCol] = null;
// Place eternal candy at new position
grid[newRow][newCol] = selectedEternalCandy;
selectedEternalCandy.row = newRow;
selectedEternalCandy.col = newCol;
// Animate teleportation with spectacular effect
tween(selectedEternalCandy, {
x: GRID_START_X + newCol * CELL_SIZE + CELL_SIZE / 2,
y: GRID_START_Y + newRow * CELL_SIZE + CELL_SIZE / 2,
scaleX: 2.0,
scaleY: 2.0,
tint: 0xFFFFFF,
alpha: 0.5
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(selectedEternalCandy, {
scaleX: 1.3,
scaleY: 1.3,
tint: 0xFFD700,
alpha: 1.0
}, {
duration: 300,
easing: tween.easeOut
});
}
});
// Update eternal candy position tracking
for (var i = 0; i < eternalCandies.length; i++) {
if (eternalCandies[i].row === oldRow && eternalCandies[i].col === oldCol) {
eternalCandies[i].row = newRow;
eternalCandies[i].col = newCol;
break;
}
}
// Create teleportation effect
LK.effects.flashScreen(0xFFD700, 600);
// Reset selection
selectedEternalCandy.graphics.tint = 0xFFD700;
selectedEternalCandy = null;
// Process matches after teleportation
LK.setTimeout(function () {
// Check for matches at new position
processMatches();
}, 500);
return;
}
// Click-to-select then click-to-swap mode
if (selectedCandy === null) {
// Check if player has reached 3 consecutive combos and should activate hourglass
if (hourglassCount > 0 && cascadeComboCount >= 3) {
// Use hourglass to maintain super combo level
hourglassCount--;
// Keep combo at super combo level (level 3)
cascadeComboCount = 3;
savedComboCount = 3;
lastCascadeTime = Date.now();
// Show hourglass activation notification
var hourglassUseNotification = new Text2('HOURGLASS ACTIVATED! SUPER COMBO MAINTAINED!', {
size: 65,
fill: '#FFD700'
});
hourglassUseNotification.anchor.set(0.5, 0.5);
hourglassUseNotification.x = 1024;
hourglassUseNotification.y = 1200;
hourglassUseNotification.alpha = 0;
game.addChild(hourglassUseNotification);
tween(hourglassUseNotification, {
alpha: 1,
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 500,
easing: tween.bounceOut,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(hourglassUseNotification, {
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
if (hourglassUseNotification.parent) {
hourglassUseNotification.parent.removeChild(hourglassUseNotification);
}
}
});
}, 2000);
}
});
// Show current combo display
if (cascadeComboCount >= 1 && cascadeComboCount <= 7) {
showCascadeComboDisplay(cascadeComboCount);
}
updateUI();
LK.getSound('powerup').play();
}
// Check if clicking on a supernova - activate it directly (but not if just created)
if (candy.isSpecial && candy.specialType === 'supernova' && !candy.justCreated) {
isProcessing = true;
activateSpecialCandy(candy);
return;
}
// First click - select candy
selectedCandy = candy;
// Visual feedback for selected candy
candy.graphics.tint = 0x00FF00; // Green tint for selection
tween(candy, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 100
});
} else if (selectedCandy === candy) {
// Clicking same candy - deselect
selectedCandy.graphics.tint = 0xFFFFFF;
tween(selectedCandy, {
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 100
});
selectedCandy = null;
} else {
// Second click - try to swap with selected candy or activate special
var tempSelectedCandy = selectedCandy;
// Check if clicking on a supernova - activate it directly (but not if just created)
if (candy.isSpecial && candy.specialType === 'supernova' && !candy.justCreated) {
selectedCandy.graphics.tint = 0xFFFFFF;
tween(selectedCandy, {
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 100
});
selectedCandy = null;
isProcessing = true;
activateSpecialCandy(candy);
return;
}
// Check if candies are adjacent
var dx = Math.abs(tempSelectedCandy.col - candy.col);
var dy = Math.abs(tempSelectedCandy.row - candy.row);
if (dx + dy === 1) {
// Adjacent candies - perform swap
isProcessing = true;
// Reset visual effects
tempSelectedCandy.graphics.tint = 0xFFFFFF;
tween(tempSelectedCandy, {
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 100
});
selectedCandy = null;
if (swapCandies(tempSelectedCandy, candy)) {
LK.setTimeout(function () {
// Check if swap creates matches
var matches1 = checkMatch(tempSelectedCandy.row, tempSelectedCandy.col);
var matches2 = checkMatch(candy.row, candy.col);
if (matches1.length >= 3 || matches2.length >= 3 || tempSelectedCandy.isSpecial && tempSelectedCandy.specialType !== 'supernova' || candy.isSpecial && candy.specialType !== 'supernova') {
// Valid move
if (tempSelectedCandy.isSpecial && tempSelectedCandy.specialType !== 'supernova' && !tempSelectedCandy.justCreated) {
activateSpecialCandy(tempSelectedCandy);
}
if (candy.isSpecial && candy.specialType !== 'supernova' && !candy.justCreated) {
activateSpecialCandy(candy);
}
LK.setTimeout(function () {
processMatches();
}, 200);
} else {
// Invalid move, swap back with animation
swapCandies(tempSelectedCandy, candy);
isProcessing = false;
}
}, 250);
}
} else {
// Not adjacent - switch selection to new candy
tempSelectedCandy.graphics.tint = 0xFFFFFF;
tween(tempSelectedCandy, {
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 100
});
selectedCandy = candy;
candy.graphics.tint = 0x00FF00;
tween(candy, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 100
});
}
}
// Start drag tracking for drag mode (fallback)
dragStartX = x;
dragStartY = y;
dragCandy = candy;
isDragging = false;
};
game.move = function (x, y, obj) {
// Block all movement when game is won
if (gameState === 'victory') {
return; // No movement allowed after victory
}
if (isProcessing || !dragCandy) return;
var deltaX = x - dragStartX;
var deltaY = y - dragStartY;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
// Check if we've moved far enough to start dragging
if (distance > SWIPE_THRESHOLD && !isDragging) {
isDragging = true;
// Add visual feedback - slightly scale up the dragged candy
tween(dragCandy, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 100
});
dragCandy.graphics.tint = 0xFFFF00; // Yellow tint during drag
}
};
game.up = function (x, y, obj) {
// Block all up events when game is won
if (gameState === 'victory') {
return; // No up events allowed after victory
}
if (isProcessing || !dragCandy) return;
var deltaX = x - dragStartX;
var deltaY = y - dragStartY;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
// Reset visual effects
dragCandy.graphics.tint = 0xFFFFFF;
tween(dragCandy, {
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 100
});
if (distance > SWIPE_THRESHOLD) {
// Determine swipe direction
var targetCandy = null;
var absX = Math.abs(deltaX);
var absY = Math.abs(deltaY);
if (absX > absY) {
// Horizontal swipe
if (deltaX > 0) {
// Swipe right
if (dragCandy.col < GRID_SIZE - 1) {
targetCandy = grid[dragCandy.row][dragCandy.col + 1];
}
} else {
// Swipe left
if (dragCandy.col > 0) {
targetCandy = grid[dragCandy.row][dragCandy.col - 1];
}
}
} else {
// Vertical swipe
if (deltaY > 0) {
// Swipe down
if (dragCandy.row < GRID_SIZE - 1) {
targetCandy = grid[dragCandy.row + 1][dragCandy.col];
}
} else {
// Swipe up
if (dragCandy.row > 0) {
targetCandy = grid[dragCandy.row - 1][dragCandy.col];
}
}
}
// If we have a valid target, try to swap
if (targetCandy) {
var tempSelectedCandy = dragCandy;
selectedCandy = null;
isProcessing = true;
if (swapCandies(tempSelectedCandy, targetCandy)) {
LK.setTimeout(function () {
// Check if swap creates matches
var matches1 = checkMatch(tempSelectedCandy.row, tempSelectedCandy.col);
var matches2 = checkMatch(targetCandy.row, targetCandy.col);
if (matches1.length >= 3 || matches2.length >= 3 || tempSelectedCandy.isSpecial && tempSelectedCandy.specialType !== 'supernova' || targetCandy.isSpecial && targetCandy.specialType !== 'supernova') {
// Valid move
if (tempSelectedCandy.isSpecial && tempSelectedCandy.specialType !== 'supernova' && !tempSelectedCandy.justCreated) {
activateSpecialCandy(tempSelectedCandy);
}
if (targetCandy.isSpecial && targetCandy.specialType !== 'supernova' && !targetCandy.justCreated) {
activateSpecialCandy(targetCandy);
}
LK.setTimeout(function () {
processMatches();
}, 200);
} else {
// Invalid move, swap back with animation
swapCandies(tempSelectedCandy, targetCandy);
isProcessing = false;
}
}, 250);
}
}
}
// Reset drag state
dragCandy = null;
dragStartX = 0;
dragStartY = 0;
isDragging = false;
selectedCandy = null;
};
function activateSecretMode() {
secretMode = true;
secretClickSequence = [];
updateUI();
// Backup current grid state
secretGridBackup = [];
for (var row = 0; row < GRID_SIZE; row++) {
secretGridBackup[row] = [];
for (var col = 0; col < GRID_SIZE; col++) {
secretGridBackup[row][col] = grid[row][col];
}
}
// Clear everything from screen
for (var row = 0; row < GRID_SIZE; row++) {
for (var col = 0; col < GRID_SIZE; col++) {
if (grid[row][col] && grid[row][col].parent) {
grid[row][col].parent.removeChild(grid[row][col]);
}
grid[row][col] = null;
}
}
// Hide UI elements
tween(scoreText, {
alpha: 0
}, {
duration: 300
});
tween(levelText, {
alpha: 0
}, {
duration: 300
});
tween(goldText, {
alpha: 0
}, {
duration: 300
});
tween(comboText, {
alpha: 0
}, {
duration: 300
});
tween(progressBarBg, {
alpha: 0
}, {
duration: 300
});
// Create 4 secret balls in sequence positions
createSecretBalls();
}
function createSecretBalls() {
secretBalls = [];
var positions = [{
x: 512,
y: 683
},
// Top left quadrant
{
x: 1536,
y: 683
},
// Top right quadrant
{
x: 512,
y: 2049
},
// Bottom left quadrant
{
x: 1536,
y: 2049
} // Bottom right quadrant
];
for (var i = 0; i < 4; i++) {
var ball = LK.getAsset('discoBall', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.0,
scaleY: 1.0,
x: positions[i].x,
y: positions[i].y
});
game.addChild(ball);
secretBalls.push(ball);
// Add number text on top of each ball
var numberText = new Text2((i + 1).toString(), {
size: 120,
fill: '#FFFFFF'
});
numberText.anchor.set(0.5, 0.5);
numberText.x = positions[i].x;
numberText.y = positions[i].y - 150; // Position above the ball
game.addChild(numberText);
ball.numberText = numberText; // Store reference for cleanup
// Add continuous rotation
var _rotateBall = function rotateBall(ballRef) {
tween(ballRef, {
rotation: ballRef.rotation + Math.PI * 2
}, {
duration: 3000,
easing: tween.linear,
onFinish: function onFinish() {
if (secretMode) {
_rotateBall(ballRef);
}
}
});
};
_rotateBall(ball);
}
// Create black hole in center
var blackHole = LK.getAsset('blackHole', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.0,
scaleY: 1.0,
x: 1024,
// Center of screen
y: 1366 // Center of screen
});
game.addChild(blackHole);
secretBalls.push(blackHole); // Add to secretBalls for cleanup
// Add pulsing animation to black hole
var _pulseBlackHole = function pulseBlackHole() {
tween(blackHole, {
scaleX: 1.3,
scaleY: 1.3,
alpha: 0.7
}, {
duration: 1500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(blackHole, {
scaleX: 1.0,
scaleY: 1.0,
alpha: 1.0
}, {
duration: 1500,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (secretMode) {
_pulseBlackHole();
}
}
});
}
});
};
_pulseBlackHole();
}
function handleSecretBallClick(ballIndex) {
secretClickSequence.push(ballIndex);
// Flash the clicked ball
var ball = secretBalls[ballIndex];
tween(ball, {
tint: 0xFFFFFF,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 200,
onFinish: function onFinish() {
tween(ball, {
tint: 0xFFFFFF,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 200
});
}
});
// Check if sequence is correct: 1st ball, 1st ball, 1st ball, 3rd ball (indices 0,0,0,2)
if (secretClickSequence.length >= 4) {
if (secretClickSequence[0] === 0 && secretClickSequence[1] === 0 && secretClickSequence[2] === 0 && secretClickSequence[3] === 2) {
// Correct sequence - restore game with special candies
restoreGameWithSpecialCandies();
} else {
// Wrong sequence - reset
secretClickSequence = [];
}
}
}
function restoreGameWithSpecialCandies() {
// Remove secret balls and their number texts
for (var i = 0; i < secretBalls.length; i++) {
if (secretBalls[i].parent) {
secretBalls[i].parent.removeChild(secretBalls[i]);
}
// Remove the number text as well
if (secretBalls[i].numberText && secretBalls[i].numberText.parent) {
secretBalls[i].numberText.parent.removeChild(secretBalls[i].numberText);
}
}
secretBalls = [];
// Restore grid with only special candies
for (var row = 0; row < GRID_SIZE; row++) {
for (var col = 0; col < GRID_SIZE; col++) {
var specialTypes = ['discoBall', 'redRocket', 'blueBomb', 'blackHole', 'supernova', 'expires', 'writerpir', 'vriper', 'converter'];
var randomSpecialType = specialTypes[Math.floor(Math.random() * specialTypes.length)];
// Create candy with original color but make it special
var originalColor = COLORS[Math.floor(Math.random() * COLORS.length)];
var candy = new Candy(originalColor, row, col);
candy.x = GRID_START_X + col * CELL_SIZE + CELL_SIZE / 2;
candy.y = GRID_START_Y + row * CELL_SIZE + CELL_SIZE / 2;
// Make it special immediately
candy.makeSpecial(randomSpecialType);
grid[row][col] = candy;
game.addChild(candy);
}
}
// Show UI elements again
tween(scoreText, {
alpha: 1
}, {
duration: 300
});
tween(levelText, {
alpha: 1
}, {
duration: 300
});
tween(goldText, {
alpha: 1
}, {
duration: 300
});
tween(progressBarBg, {
alpha: 1
}, {
duration: 300
});
// Set unlimited gold for test mode
gold = 999999999;
storage.gold = gold;
updateUI();
// Set 20x score multiplier for matches
comboMultiplier = 20;
showComboDisplay();
// Activate special candy spawning mode
onlySpecialCandies = true;
secretMode = false;
isProcessing = false;
}
function restartGame() {
// Reset all game variables to initial state
score = 0;
level = 1;
gold = 0;
storage.gold = gold;
inventory = {};
storage.inventory = inventory;
isProcessing = false;
comboMultiplier = 1;
selectedCandy = null;
// Reset secret feature variables
secretMode = false;
secretBalls = [];
secretClickSequence = [];
secretGridBackup = null;
onlySpecialCandies = false;
// Clear all secret balls and their number texts
for (var i = 0; i < secretBalls.length; i++) {
if (secretBalls[i].parent) {
secretBalls[i].parent.removeChild(secretBalls[i]);
}
// Remove the number text as well
if (secretBalls[i].numberText && secretBalls[i].numberText.parent) {
secretBalls[i].numberText.parent.removeChild(secretBalls[i].numberText);
}
}
secretBalls = [];
// Clear current grid completely
for (var row = 0; row < GRID_SIZE; row++) {
for (var col = 0; col < GRID_SIZE; col++) {
if (grid[row][col] && grid[row][col].parent) {
grid[row][col].parent.removeChild(grid[row][col]);
}
grid[row][col] = null;
}
}
// Show UI elements again
tween(scoreText, {
alpha: 1
}, {
duration: 300
});
tween(levelText, {
alpha: 1
}, {
duration: 300
});
tween(goldText, {
alpha: 1
}, {
duration: 300
});
tween(comboText, {
alpha: 0
}, {
duration: 300
});
tween(progressBarBg, {
alpha: 1
}, {
duration: 300
});
// Reset progress bar
progressBarFill.scaleX = 0;
// Reinitialize grid with fresh candies
initializeGrid();
removeInitialMatches();
// Update UI to show reset values
updateUI();
}
function returnToNormalGame() {
// Remove secret balls and their number texts
for (var i = 0; i < secretBalls.length; i++) {
if (secretBalls[i].parent) {
secretBalls[i].parent.removeChild(secretBalls[i]);
}
// Remove the number text as well
if (secretBalls[i].numberText && secretBalls[i].numberText.parent) {
secretBalls[i].numberText.parent.removeChild(secretBalls[i].numberText);
}
}
secretBalls = [];
// Clear current grid completely before restoring
for (var row = 0; row < GRID_SIZE; row++) {
for (var col = 0; col < GRID_SIZE; col++) {
if (grid[row][col] && grid[row][col].parent) {
grid[row][col].parent.removeChild(grid[row][col]);
}
grid[row][col] = null;
}
}
// Restore original grid state from backup
for (var row = 0; row < GRID_SIZE; row++) {
for (var col = 0; col < GRID_SIZE; col++) {
if (secretGridBackup && secretGridBackup[row] && secretGridBackup[row][col]) {
var originalCandy = secretGridBackup[row][col];
originalCandy.x = GRID_START_X + col * CELL_SIZE + CELL_SIZE / 2;
originalCandy.y = GRID_START_Y + row * CELL_SIZE + CELL_SIZE / 2;
grid[row][col] = originalCandy;
game.addChild(originalCandy);
}
}
}
// Show UI elements again
tween(scoreText, {
alpha: 1
}, {
duration: 300
});
tween(levelText, {
alpha: 1
}, {
duration: 300
});
tween(goldText, {
alpha: 1
}, {
duration: 300
});
tween(progressBarBg, {
alpha: 1
}, {
duration: 300
});
// Reset to normal game state
comboMultiplier = 1;
showComboDisplay();
onlySpecialCandies = false;
secretMode = false;
isProcessing = false;
secretGridBackup = null;
}
// Create save button
var saveButton = LK.getAsset('greenCandy', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.0,
scaleY: 0.6
});
saveButton.x = 1024;
saveButton.y = 2600;
gameContainer.addChild(saveButton);
var saveButtonText = new Text2('SAVE GAME', {
size: 50,
fill: '#FFFFFF'
});
saveButtonText.anchor.set(0.5, 0.5);
saveButtonText.x = 1024;
saveButtonText.y = 2600;
gameContainer.addChild(saveButtonText);
// Try to load saved game state on startup
LK.setTimeout(function () {
if (storage.savedScore !== undefined) {
score = storage.savedScore || 0;
level = storage.savedLevel || 1;
gold = storage.savedGold || 0;
inventory = storage.savedInventory || {};
hourglassCount = storage.savedHourglassCount || 0;
savedComboCount = storage.savedComboCount || 0;
yellowCandiesClicked = storage.savedYellowCandiesClicked || [];
storage.gold = gold;
storage.inventory = inventory;
updateUI();
gameStateSaved = true;
// Show loaded message
var loadedText = new Text2('Game Loaded!', {
size: 60,
fill: '#00FF00'
});
loadedText.anchor.set(0.5, 0.5);
loadedText.x = 1024;
loadedText.y = 2500;
loadedText.alpha = 0;
game.addChild(loadedText);
tween(loadedText, {
alpha: 1
}, {
duration: 500,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(loadedText, {
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
if (loadedText.parent) {
loadedText.parent.removeChild(loadedText);
}
}
});
}, 2000);
}
});
}
// Load achievements from storage
if (storage.smallCollectorAchieved) {
achievements.smallCollector = true;
}
if (storage.hiddenStarsAchieved) {
achievements.hiddenStars = true;
}
if (storage.leaguesAchieved) {
achievements.leagues = true;
}
if (storage.universeAchieved) {
achievements.universe = true;
}
}, 1000);
// Menu navigation functions
function showMainMenu() {
gameState = 'menu';
// Show main menu
mainMenuContainer.alpha = 1;
// Hide other menus and game
if (settingsMenuContainer) settingsMenuContainer.alpha = 0;
if (statisticsMenuContainer) statisticsMenuContainer.alpha = 0;
if (savesMenuContainer) savesMenuContainer.alpha = 0;
if (gameContainer) gameContainer.alpha = 0;
}
function showSettingsMenu() {
gameState = 'settings';
// Hide main menu
mainMenuContainer.alpha = 0;
// Show settings menu with animation
tween(settingsMenuContainer, {
alpha: 1
}, {
duration: 300,
easing: tween.easeOut
});
}
function showStatisticsMenu() {
gameState = 'statistics';
// Hide main menu
mainMenuContainer.alpha = 0;
// Show statistics menu with animation
tween(statisticsMenuContainer, {
alpha: 1
}, {
duration: 300,
easing: tween.easeOut
});
}
function showSavesMenu() {
gameState = 'saves';
savesMenuMode = 'save';
// Hide main menu
mainMenuContainer.alpha = 0;
// Refresh saves menu to show current data
refreshSavesMenu();
// Show saves menu with animation
tween(savesMenuContainer, {
alpha: 1
}, {
duration: 300,
easing: tween.easeOut
});
}
function showSavesMenuForLoad() {
gameState = 'saves';
savesMenuMode = 'load';
// Hide main menu
mainMenuContainer.alpha = 0;
// Refresh saves menu to show current data
refreshSavesMenu();
// Show saves menu with animation
tween(savesMenuContainer, {
alpha: 1
}, {
duration: 300,
easing: tween.easeOut
});
}
function saveGameToSlot(slotIndex) {
// Save current game state to the selected slot using individual storage properties
var slotPrefix = 'saveSlot' + (slotIndex + 1) + '_';
storage[slotPrefix + 'score'] = score;
storage[slotPrefix + 'level'] = level;
storage[slotPrefix + 'gold'] = gold;
storage[slotPrefix + 'hourglassCount'] = hourglassCount;
storage[slotPrefix + 'savedComboCount'] = savedComboCount;
storage[slotPrefix + 'timestamp'] = Date.now();
// Save arrays as individual indexed items since storage doesn't support nested objects
storage[slotPrefix + 'yellowCandiesClickedCount'] = yellowCandiesClicked.length;
for (var i = 0; i < yellowCandiesClicked.length; i++) {
storage[slotPrefix + 'yellowCandiesClicked_' + i] = yellowCandiesClicked[i];
}
// Mark slot as having saved data
storage[slotPrefix + 'hasSave'] = true;
// Show save confirmation
var savedText = new Text2('Slot ' + (slotIndex + 1) + ' Kaydedildi!', {
size: 70,
fill: '#00FF00'
});
savedText.anchor.set(0.5, 0.5);
savedText.x = 1024;
savedText.y = 2200;
savedText.alpha = 0;
game.addChild(savedText);
tween(savedText, {
alpha: 1
}, {
duration: 500,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(savedText, {
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
if (savedText.parent) {
savedText.parent.removeChild(savedText);
}
}
});
}, 2000);
}
});
// Refresh the saves menu to show updated slot
refreshSavesMenu();
}
function loadGameFromSlot(slotIndex) {
// Load game state from the selected slot using individual storage properties
var slotPrefix = 'saveSlot' + (slotIndex + 1) + '_';
var hasSave = storage[slotPrefix + 'hasSave'];
if (!hasSave) {
// Show message that slot is empty
var emptySlotText = new Text2('Bu slot boş!', {
size: 70,
fill: '#FF0000'
});
emptySlotText.anchor.set(0.5, 0.5);
emptySlotText.x = 1024;
emptySlotText.y = 2200;
emptySlotText.alpha = 0;
game.addChild(emptySlotText);
tween(emptySlotText, {
alpha: 1
}, {
duration: 500,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(emptySlotText, {
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
if (emptySlotText.parent) {
emptySlotText.parent.removeChild(emptySlotText);
}
}
});
}, 2000);
}
});
return;
}
// Load the saved game state
score = storage[slotPrefix + 'score'] || 0;
level = storage[slotPrefix + 'level'] || 1;
gold = storage[slotPrefix + 'gold'] || 0;
hourglassCount = storage[slotPrefix + 'hourglassCount'] || 0;
savedComboCount = storage[slotPrefix + 'savedComboCount'] || 0;
// Load yellow candies clicked array
yellowCandiesClicked = [];
var yellowCandiesCount = storage[slotPrefix + 'yellowCandiesClickedCount'] || 0;
for (var i = 0; i < yellowCandiesCount; i++) {
var candyId = storage[slotPrefix + 'yellowCandiesClicked_' + i];
if (candyId) {
yellowCandiesClicked.push(candyId);
}
}
// Save gold to storage
storage.gold = gold;
// Show load confirmation
var loadedText = new Text2('Slot ' + (slotIndex + 1) + ' Yüklendi!', {
size: 70,
fill: '#00FF00'
});
loadedText.anchor.set(0.5, 0.5);
loadedText.x = 1024;
loadedText.y = 2200;
loadedText.alpha = 0;
game.addChild(loadedText);
tween(loadedText, {
alpha: 1
}, {
duration: 500,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(loadedText, {
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
if (loadedText.parent) {
loadedText.parent.removeChild(loadedText);
}
}
});
}, 2000);
}
});
// Start the game with loaded state
LK.setTimeout(function () {
startGame();
}, 1500);
}
function refreshSavesMenu() {
// Remove existing saves menu and recreate it with updated data
if (savesMenuContainer && savesMenuContainer.parent) {
savesMenuContainer.parent.removeChild(savesMenuContainer);
}
createSavesMenu();
}
function startGame() {
gameState = 'playing';
// Hide all menus
mainMenuContainer.alpha = 0;
if (settingsMenuContainer) settingsMenuContainer.alpha = 0;
// Check if player name exists, if not ask for it
var currentPlayerName = storage.currentPlayerName;
if (!currentPlayerName) {
// Show name input dialog
showPlayerNameInput();
return;
}
// Add current player to the list if not already there
addPlayerToList(currentPlayerName);
// Show game with animation
tween(gameContainer, {
alpha: 1
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
// Initialize the game after animation
initializeGrid();
removeInitialMatches();
// Give starting gold for new market experience
gold = 1000;
storage.gold = gold;
// Increment games played counter
if (!storage.gamesPlayed) {
storage.gamesPlayed = 0;
}
storage.gamesPlayed++;
updateUI();
LK.playMusic('7week3days');
}
});
}
// Start with main menu visible
showMainMenu();
;
// Track current cascade combo text to prevent overlapping
var currentCascadeText = null;
function showCascadeComboDisplay(comboLevel) {
if (comboLevel < 1 || comboLevel > 7) return;
var comboName = cascadeComboNames[comboLevel];
if (!comboName) return;
// Remove previous cascade text immediately if it exists
if (currentCascadeText && currentCascadeText.parent) {
tween.stop(currentCascadeText);
currentCascadeText.parent.removeChild(currentCascadeText);
currentCascadeText = null;
}
// Create cascade combo text
var cascadeText = new Text2(comboName, {
size: 100 + comboLevel * 20,
// Size increases with combo level
fill: comboLevel <= 2 ? '#FFFF00' : comboLevel <= 4 ? '#FF8C00' : comboLevel <= 6 ? '#FF0000' : '#FFD700' // Colors get more intense
});
cascadeText.anchor.set(0.5, 0.5);
cascadeText.x = 1024;
cascadeText.y = 1000; // Position below center
cascadeText.alpha = 0;
cascadeText.scaleX = 0.3;
cascadeText.scaleY = 0.3;
game.addChild(cascadeText);
// Set as current cascade text
currentCascadeText = cascadeText;
// Animate cascade text with increasing intensity
var animationDuration = Math.max(800 - comboLevel * 50, 300); // Faster for higher combos
tween(cascadeText, {
alpha: 1,
scaleX: 1.0 + comboLevel * 0.2,
scaleY: 1.0 + comboLevel * 0.2,
rotation: comboLevel % 2 === 0 ? 0.1 : -0.1 // Alternate rotation
}, {
duration: animationDuration,
easing: tween.bounceOut,
onFinish: function onFinish() {
// Hold briefly then fade out
LK.setTimeout(function () {
tween(cascadeText, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 400,
easing: tween.easeIn,
onFinish: function onFinish() {
if (cascadeText.parent) {
cascadeText.parent.removeChild(cascadeText);
}
// Clear reference if this is still the current text
if (currentCascadeText === cascadeText) {
currentCascadeText = null;
}
}
});
}, 1000 + comboLevel * 200); // Hold longer for higher combos
}
});
// Add screen flash effect for higher combos
if (comboLevel >= 3) {
var flashColor = comboLevel <= 4 ? 0xFF8C00 : comboLevel <= 6 ? 0xFF0000 : 0xFFD700;
var flashDuration = Math.min(200 + comboLevel * 100, 800);
LK.effects.flashScreen(flashColor, flashDuration);
}
// Play sound effect
LK.getSound('powerup').play();
}
function createSupernovaReward() {
// Find a random empty position or replace a regular candy
var availablePositions = [];
for (var row = 0; row < GRID_SIZE; row++) {
for (var col = 0; col < GRID_SIZE; col++) {
if (!grid[row][col] || !grid[row][col].isSpecial && Math.random() < 0.3) {
availablePositions.push({
row: row,
col: col
});
}
}
}
if (availablePositions.length > 0) {
var randomPos = availablePositions[Math.floor(Math.random() * availablePositions.length)];
var row = randomPos.row;
var col = randomPos.col;
// Remove existing candy if present
if (grid[row][col] && grid[row][col].parent) {
grid[row][col].parent.removeChild(grid[row][col]);
}
// Create supernova reward
var rewardColor = COLORS[Math.floor(Math.random() * COLORS.length)];
var supernovaReward = new Candy(rewardColor, row, col);
supernovaReward.x = GRID_START_X + col * CELL_SIZE + CELL_SIZE / 2;
supernovaReward.y = GRID_START_Y + row * CELL_SIZE + CELL_SIZE / 2;
supernovaReward.makeSpecial('supernova');
grid[row][col] = supernovaReward;
game.addChild(supernovaReward);
// Add spectacular creation effect for the reward
tween(supernovaReward.graphics, {
scaleX: 2.0,
scaleY: 2.0,
tint: 0xFFD700,
rotation: Math.PI * 4
}, {
duration: 1500,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Add continuous pulsing glow effect
var _pulseSuperNova = function pulseSuperNova() {
if (supernovaReward && supernovaReward.isSpecial && supernovaReward.specialType === 'supernova' && supernovaReward.parent) {
tween(supernovaReward.graphics, {
scaleX: 1.5,
scaleY: 1.5,
tint: 0xFFFF00
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(supernovaReward.graphics, {
scaleX: 1.3,
scaleY: 1.3,
tint: 0xFFFFFF
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
LK.setTimeout(_pulseSuperNova, 200);
}
});
}
});
}
};
_pulseSuperNova();
}
});
// Add massive bonus for 7th cascade combo
score += 50000;
gold += 25000;
updateUI();
// Show special reward text
var rewardText = new Text2('SUPERNOVA REWARD!', {
size: 140,
fill: '#FFD700'
});
rewardText.anchor.set(0.5, 0.5);
rewardText.x = 1024;
rewardText.y = 800;
rewardText.alpha = 0;
rewardText.scaleX = 0.2;
rewardText.scaleY = 0.2;
game.addChild(rewardText);
tween(rewardText, {
alpha: 1,
scaleX: 1.5,
scaleY: 1.5,
rotation: 0.1
}, {
duration: 1000,
easing: tween.bounceOut,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(rewardText, {
alpha: 0,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 500,
easing: tween.easeIn,
onFinish: function onFinish() {
if (rewardText.parent) {
rewardText.parent.removeChild(rewardText);
}
}
});
}, 2000);
}
});
// Create spectacular screen effects
LK.effects.flashScreen(0xFFD700, 1500);
}
}
function showLevelUpNotification(reachedLevel) {
// Create level up notification text
var levelUpText = new Text2('LEVEL ' + reachedLevel + ' REACHED!', {
size: 120,
fill: '#FFD700'
});
levelUpText.anchor.set(0.5, 0.5);
levelUpText.x = 1024;
levelUpText.y = 1366;
levelUpText.alpha = 0;
levelUpText.scaleX = 0.5;
levelUpText.scaleY = 0.5;
game.addChild(levelUpText);
// Animate level text appearing
tween(levelUpText, {
alpha: 1,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 500,
easing: tween.bounceOut,
onFinish: function onFinish() {
// Hold for a moment then fade out
LK.setTimeout(function () {
tween(levelUpText, {
alpha: 0,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {
if (levelUpText.parent) {
levelUpText.parent.removeChild(levelUpText);
}
// Show SUGERCRUSH text after level text disappears
showSugercrushText();
}
});
}, 1500);
}
});
}
function showSugercrushText() {
// Create SUGERCRUSH text
var sugercrushText = new Text2('SUGERCRUSH', {
size: 150,
fill: '#FF6B35'
});
sugercrushText.anchor.set(0.5, 0.5);
sugercrushText.x = 1024;
sugercrushText.y = 1366;
sugercrushText.alpha = 0;
sugercrushText.scaleX = 0.3;
sugercrushText.scaleY = 0.3;
sugercrushText.rotation = -0.2;
game.addChild(sugercrushText);
// Animate SUGERCRUSH text with spectacular effect
tween(sugercrushText, {
alpha: 1,
scaleX: 1.5,
scaleY: 1.5,
rotation: 0.2
}, {
duration: 800,
easing: tween.bounceOut,
onFinish: function onFinish() {
// Add pulsing effect
var pulseCount = 0;
var maxPulses = 3;
var _pulseEffect = function pulseEffect() {
if (pulseCount < maxPulses) {
tween(sugercrushText, {
scaleX: 1.8,
scaleY: 1.8,
tint: 0xFFD700
}, {
duration: 200,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(sugercrushText, {
scaleX: 1.5,
scaleY: 1.5,
tint: 0xFFFFFF
}, {
duration: 200,
easing: tween.easeInOut,
onFinish: function onFinish() {
pulseCount++;
LK.setTimeout(_pulseEffect, 100);
}
});
}
});
} else {
// Final fade out
LK.setTimeout(function () {
tween(sugercrushText, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5,
rotation: 0.5
}, {
duration: 500,
easing: tween.easeIn,
onFinish: function onFinish() {
if (sugercrushText.parent) {
sugercrushText.parent.removeChild(sugercrushText);
}
}
});
}, 1000);
}
};
_pulseEffect();
}
});
// Add screen flash effect
LK.effects.flashScreen(0xFF6B35, 300);
}
function checkSmallCollectorAchievement() {
// Check if all balls have been clicked to small size
if (!achievements.smallCollector && ballsClickedSmall.length >= totalBallsToClick && totalBallsToClick > 0) {
// Achievement unlocked!
achievements.smallCollector = true;
// Save achievement to storage
storage.smallCollectorAchieved = true;
// Award +5000 gold
gold += 5000;
storage.gold = gold;
updateUI();
// Show achievement notification
showAchievementNotification('SMALL COLLECTOR', 'All balls clicked small!', '+5000 Gold');
// Play achievement sound
LK.getSound('powerup').play();
}
}
function checkHiddenStarsAchievement() {
// Check if the sequence 1, 1, 1, 3 has been entered after clicking shooting star
if (!achievements.hiddenStars && hiddenStarsActivated && hiddenStarsSequence.length >= 4) {
if (hiddenStarsSequence[0] === 1 && hiddenStarsSequence[1] === 1 && hiddenStarsSequence[2] === 1 && hiddenStarsSequence[3] === 3) {
// Achievement unlocked!
achievements.hiddenStars = true;
// Save achievement to storage
storage.hiddenStarsAchieved = true;
// Award +8000 gold
gold += 8000;
// Ensure gold is saved to storage
storage.gold = gold;
updateUI();
// Show achievement notification
showAchievementNotification('HIDDEN STARS', 'Secret sequence discovered!', '+8000 Gold');
// Play achievement sound
LK.getSound('powerup').play();
// Reset the tracking variables
hiddenStarsActivated = false;
hiddenStarsSequence = [];
}
}
}
function checkLeaguesAchievement() {
// Check if player has reached level 4
if (!achievements.leagues && level >= 4) {
// Achievement unlocked!
achievements.leagues = true;
// Save achievement to storage
storage.leaguesAchieved = true;
// Add special rewards to map: 1 supernova, 1 Karadeniz, 2 writerpir
var rewardsAdded = 0;
var maxRewards = 4;
// Find positions to place rewards
for (var row = 0; row < GRID_SIZE && rewardsAdded < maxRewards; row++) {
for (var col = 0; col < GRID_SIZE && rewardsAdded < maxRewards; col++) {
if (grid[row][col] && !grid[row][col].isSpecial && Math.random() < 0.3) {
var rewardType;
if (rewardsAdded === 0) {
rewardType = 'supernova'; // 1 supernova
} else if (rewardsAdded === 1) {
rewardType = 'expires'; // 1 Karadeniz (using expires asset)
} else {
rewardType = 'writerpir'; // 2 writerpir
}
// Transform existing candy into reward
grid[row][col].makeSpecial(rewardType);
// Add creation sparkle effect
tween(grid[row][col].graphics, {
scaleX: 1.3,
scaleY: 1.3,
tint: 0xFFD700
}, {
duration: 500,
easing: tween.bounceOut
});
rewardsAdded++;
}
}
}
updateUI();
// Show achievement notification
showAchievementNotification('LEAGUES', 'Reached Level 4!', 'Special rewards added to map!');
// Play achievement sound
LK.getSound('powerup').play();
}
}
function checkUniverseAchievement() {
// Check if a Karadeniz (expires) has been produced
if (!achievements.universe) {
// Achievement unlocked!
achievements.universe = true;
// Save achievement to storage
storage.universeAchieved = true;
// Award +2000 gold
gold += 2000;
storage.gold = gold;
updateUI();
// Show achievement notification
showAchievementNotification('UNIVERSE', 'Karadeniz produced!', '+2000 Gold');
// Play achievement sound
LK.getSound('powerup').play();
}
}
function checkTimelessKaradenizCombinations(allMatches) {
// First check for timeless Karadeniz + timeless Karadeniz combinations
for (var m = 0; m < allMatches.length; m++) {
var matches = allMatches[m];
// Count timeless Karadeniz in this match
var timelessCount = 0;
var timelessCandies = [];
for (var i = 0; i < matches.length; i++) {
var candy = matches[i];
if (candy && candy.isTimeless && candy.specialType === 'expires') {
timelessCount++;
timelessCandies.push(candy);
}
}
// If we have 2 or more timeless Karadeniz in the same match, create warlek
if (timelessCount >= 2) {
// Create warlek effect - turn all candies purple
var firstTimeless = timelessCandies[0];
var secondTimeless = timelessCandies[1];
// Remove both timeless Karadeniz from tracking
for (var t = timelessKaradenizCandies.length - 1; t >= 0; t--) {
if (timelessKaradenizCandies[t] === firstTimeless || timelessKaradenizCandies[t] === secondTimeless) {
timelessKaradenizCandies.splice(t, 1);
}
}
// Create warlek at first timeless position
firstTimeless.makeSpecial('ultraSupernova');
firstTimeless.isTimeless = false;
firstTimeless.specialType = 'warlek';
firstTimeless.isSpecial = true;
// Remove second timeless
grid[secondTimeless.row][secondTimeless.col] = null;
secondTimeless.explode();
// Create spectacular warlek creation effect
tween(firstTimeless.graphics, {
scaleX: 3.0,
scaleY: 3.0,
tint: 0x9013fe,
rotation: Math.PI * 8
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Turn all candies purple with wave effect
turnAllCandiesPurple(firstTimeless);
}
});
// Show warlek creation notification
var warlekText = new Text2('WARLEK CREATED!', {
size: 120,
fill: '#9013fe'
});
warlekText.anchor.set(0.5, 0.5);
warlekText.x = 1024;
warlekText.y = 1366;
warlekText.alpha = 0;
game.addChild(warlekText);
tween(warlekText, {
alpha: 1,
scaleX: 1.5,
scaleY: 1.5,
rotation: 0.2
}, {
duration: 1000,
easing: tween.bounceOut,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(warlekText, {
alpha: 0,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 500,
onFinish: function onFinish() {
if (warlekText.parent) {
warlekText.parent.removeChild(warlekText);
}
}
});
}, 2000);
}
});
// Add massive bonus for warlek creation
score += 50000;
gold += 25000;
updateUI();
LK.effects.flashScreen(0x9013fe, 1500);
LK.getSound('powerup').play();
// Clear the match to prevent further processing
matches.length = 0;
return; // Exit early since warlek was created
}
}
// Check each match group for timeless Karadeniz participation
for (var m = 0; m < allMatches.length; m++) {
var matches = allMatches[m];
// Look for timeless Karadeniz in this match
for (var i = 0; i < matches.length; i++) {
var candy = matches[i];
if (candy && candy.isTimeless && candy.specialType === 'expires') {
// Found timeless Karadeniz in match - it can combine with any candy type
var combiningCandiesCount = matches.length - 1; // Exclude the timeless Karadeniz itself
candy.timelessHealth -= combiningCandiesCount;
// Update cracking effect based on new health
startCrackingEffect(candy);
// Show health status
showTimelessHealthStatus(candy);
// Explode only the combining candies, not the timeless Karadeniz
for (var j = 0; j < matches.length; j++) {
if (matches[j] !== candy) {
// This is a combining candy - explode it with score
explodeCandyWithScore(matches[j]);
grid[matches[j].row][matches[j].col] = null;
}
}
// Check if timeless Karadeniz should explode (when health reaches 0, meaning 40 candies combined)
if (candy.timelessHealth <= 0) {
// Store position for potential recreation
var timelessRow = candy.row;
var timelessCol = candy.col;
// Remove from timeless tracking array
for (var t = 0; t < timelessKaradenizCandies.length; t++) {
if (timelessKaradenizCandies[t] === candy) {
timelessKaradenizCandies.splice(t, 1);
break;
}
}
// Explode the timeless Karadeniz and entire map
explodeEntireMap(candy);
// Schedule check for new combo formation after explosion effects complete
LK.setTimeout(function () {
// Check if new combos formed at the same position after explosion
var newMatches = checkMatch(timelessRow, timelessCol);
if (newMatches.length >= 3) {
// New combo formed - recreate timeless Karadeniz
recreateTimelessKaradeniz(timelessRow, timelessCol);
}
}, 1000); // Wait for explosion effects to complete
return; // Exit early since map exploded
}
// Remove ALL candies from this match since they've been processed
// This prevents them from being processed again in the normal match logic
matches.length = 0;
break; // Only one timeless Karadeniz per match
}
}
}
// Also check for adjacent combinations with timeless Karadeniz
checkTimelessAdjacentCombinations();
}
function checkTimelessAdjacentCombinations() {
// Check if any timeless Karadeniz has adjacent candies it can combine with
for (var t = 0; t < timelessKaradenizCandies.length; t++) {
var timelessCandy = timelessKaradenizCandies[t];
if (!timelessCandy || !timelessCandy.parent) continue;
var row = timelessCandy.row;
var col = timelessCandy.col;
var adjacentPositions = [[-1, 0], [1, 0], [0, -1], [0, 1]];
// Check each adjacent position for any candy to combine with
for (var a = 0; a < adjacentPositions.length; a++) {
var adjRow = row + adjacentPositions[a][0];
var adjCol = col + adjacentPositions[a][1];
if (adjRow >= 0 && adjRow < GRID_SIZE && adjCol >= 0 && adjCol < GRID_SIZE) {
var adjacentCandy = grid[adjRow][adjCol];
// Timeless Karadeniz can combine with any candy type
if (adjacentCandy && adjacentCandy !== timelessCandy && !adjacentCandy.isTimeless) {
// Timeless Karadeniz combines with this adjacent candy directly
timelessCandy.timelessHealth -= 1; // Reduce health by 1 for each candy it combines with
// Update cracking effect
startCrackingEffect(timelessCandy);
// Show health status
showTimelessHealthStatus(timelessCandy);
// Remove the adjacent candy (it gets "consumed" by timeless Karadeniz)
explodeCandyWithScore(adjacentCandy);
grid[adjRow][adjCol] = null;
// Check if timeless Karadeniz should explode (reached 40 combinations)
if (timelessCandy.timelessHealth <= 0) {
// Remove from tracking array
for (var tr = 0; tr < timelessKaradenizCandies.length; tr++) {
if (timelessKaradenizCandies[tr] === timelessCandy) {
timelessKaradenizCandies.splice(tr, 1);
break;
}
}
// Explode entire map
explodeEntireMap(timelessCandy);
return;
}
break; // Only process one adjacent candy per timeless candy per cycle
}
}
}
}
}
function showTimelessHealthStatus(candy) {
if (!candy || !candy.isTimeless) return;
// Calculate remaining combinations needed (health represents remaining combinations)
var remainingCombinations = candy.timelessHealth;
var totalCombinations = 40;
var completedCombinations = totalCombinations - remainingCombinations;
// Create status text showing combinations progress
var statusText = new Text2(completedCombinations + '/' + totalCombinations, {
size: 60,
fill: remainingCombinations > 20 ? '#FFD700' : remainingCombinations > 10 ? '#FF8C00' : '#FF0000'
});
statusText.anchor.set(0.5, 0.5);
statusText.x = candy.x;
statusText.y = candy.y - 120;
statusText.alpha = 0;
game.addChild(statusText);
// Animate status text
tween(statusText, {
alpha: 1,
scaleX: 1.5,
scaleY: 1.5,
y: candy.y - 150
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(statusText, {
alpha: 0,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 300,
onFinish: function onFinish() {
if (statusText.parent) {
statusText.parent.removeChild(statusText);
}
}
});
}, 1000);
}
});
}
function explodeEntireMap(timelessCandy) {
// Transform timeless Karadeniz into red rocket instead of exploding
if (timelessCandy && timelessCandy.parent) {
// Remove timeless properties
timelessCandy.isTimeless = false;
timelessCandy.timelessHealth = 0;
// Transform into red rocket
timelessCandy.makeSpecial('redRocket');
timelessCandy.justCreated = true; // Prevent immediate activation
// Create transformation effect
tween(timelessCandy.graphics, {
scaleX: 1.5,
scaleY: 1.5,
tint: 0x991b1b,
rotation: Math.PI * 2
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
// Reset creation flag after animation
LK.setTimeout(function () {
if (timelessCandy && timelessCandy.parent) {
timelessCandy.justCreated = false;
}
}, 500);
}
});
// Add score bonus for transformation
score += 15000;
gold += 7500;
updateUI();
// Create transformation effects
LK.effects.flashScreen(0x991b1b, 1000);
// Show transformation notification
var transformText = new Text2('TIMELESS KARADENIZ → RED ROCKET!', {
size: 100,
fill: '#991b1b'
});
transformText.anchor.set(0.5, 0.5);
transformText.x = 1024;
transformText.y = 1366;
transformText.alpha = 0;
transformText.scaleX = 0.5;
transformText.scaleY = 0.5;
game.addChild(transformText);
tween(transformText, {
alpha: 1,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 800,
easing: tween.bounceOut,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(transformText, {
alpha: 0,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 500,
onFinish: function onFinish() {
if (transformText.parent) {
transformText.parent.removeChild(transformText);
}
}
});
}, 2000);
}
});
}
}
function startCrackingEffect(candy) {
if (!candy || !candy.isTimeless || !candy.parent) return;
// Calculate crack intensity based on combination progress (40 total combinations needed)
var totalCombinations = 40;
var completedCombinations = totalCombinations - candy.timelessHealth;
var crackIntensity = completedCombinations / totalCombinations; // More cracks as more combinations completed
// Create cracking visual effect with scale pulsing
var pulseScale = 1.0 + crackIntensity * 0.5; // More intense pulsing as more combinations completed
var pulseSpeed = Math.max(2000 - crackIntensity * 1500, 300); // Faster pulsing as more combinations completed
// Apply cracking tint - gets redder as more combinations completed
var crackTint = 0xFF4500; // Orange base
if (crackIntensity > 0.75) {
crackTint = 0xFF0000; // Red when close to explosion (30+ combinations)
} else if (crackIntensity > 0.5) {
crackTint = 0xFF2500; // Dark orange when moderately damaged (20+ combinations)
} else if (crackIntensity > 0.25) {
crackTint = 0xFF3500; // Light orange when lightly damaged (10+ combinations)
}
tween(candy.graphics, {
scaleX: pulseScale,
scaleY: pulseScale,
tint: crackTint,
alpha: 0.8 + crackIntensity * 0.2
}, {
duration: pulseSpeed / 2,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (candy && candy.isTimeless && candy.parent) {
tween(candy.graphics, {
scaleX: 0.8,
scaleY: 0.8,
alpha: 1.0
}, {
duration: pulseSpeed / 2,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Continue cracking effect if still timeless and alive
if (candy && candy.isTimeless && candy.parent && candy.timelessHealth > 0) {
LK.setTimeout(function () {
startCrackingEffect(candy);
}, 100);
}
}
});
}
}
});
}
function showAchievementNotification(title, description, reward) {
// Create achievement notification background
var achievementBg = LK.getAsset('progressBarBg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.0,
scaleY: 3.0
});
achievementBg.x = 1024;
achievementBg.y = 1366;
achievementBg.alpha = 0;
game.addChild(achievementBg);
// Create achievement title text
var titleText = new Text2(title, {
size: 80,
fill: '#FFD700'
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 1266;
titleText.alpha = 0;
game.addChild(titleText);
// Create achievement description text
var descText = new Text2(description, {
size: 60,
fill: '#FFFFFF'
});
descText.anchor.set(0.5, 0.5);
descText.x = 1024;
descText.y = 1366;
descText.alpha = 0;
game.addChild(descText);
// Create achievement reward text
var rewardText = new Text2(reward, {
size: 70,
fill: '#00FF00'
});
rewardText.anchor.set(0.5, 0.5);
rewardText.x = 1024;
rewardText.y = 1466;
rewardText.alpha = 0;
game.addChild(rewardText);
// Animate achievement notification appearing
tween(achievementBg, {
alpha: 0.9,
scaleX: 2.2,
scaleY: 3.2
}, {
duration: 300,
easing: tween.bounceOut
});
tween(titleText, {
alpha: 1,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 400,
easing: tween.bounceOut
});
tween(descText, {
alpha: 1
}, {
duration: 500,
easing: tween.easeOut
});
tween(rewardText, {
alpha: 1,
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 600,
easing: tween.bounceOut,
onFinish: function onFinish() {
// Hold for a moment then fade out
LK.setTimeout(function () {
// Fade out all elements
tween(achievementBg, {
alpha: 0,
scaleX: 1.8,
scaleY: 2.8
}, {
duration: 500,
easing: tween.easeIn
});
tween(titleText, {
alpha: 0,
scaleY: 0.8
}, {
duration: 500,
easing: tween.easeIn
});
tween(descText, {
alpha: 0
}, {
duration: 500,
easing: tween.easeIn
});
tween(rewardText, {
alpha: 0,
scaleY: 0.8
}, {
duration: 500,
easing: tween.easeIn,
onFinish: function onFinish() {
// Clean up elements
if (achievementBg.parent) achievementBg.parent.removeChild(achievementBg);
if (titleText.parent) titleText.parent.removeChild(titleText);
if (descText.parent) descText.parent.removeChild(descText);
if (rewardText.parent) rewardText.parent.removeChild(rewardText);
}
});
}, 3000);
}
});
// Add screen flash effect
LK.effects.flashScreen(0xFFD700, 500);
}
;
function recreateTimelessKaradeniz(row, col) {
// Check if position is valid and has a candy
if (row >= 0 && row < GRID_SIZE && col >= 0 && col < GRID_SIZE && grid[row] && grid[row][col]) {
var candy = grid[row][col];
// Transform candy into timeless Karadeniz
candy.makeSpecial('expires');
candy.isTimeless = true;
candy.timelessHealth = 40; // Reset with full health
candy.maxTimelessHealth = 40;
// Add to timeless tracking array
timelessKaradenizCandies.push(candy);
// Create recreation effect
tween(candy.graphics, {
scaleX: 1.8,
scaleY: 1.8,
tint: 0xFF4500,
rotation: Math.PI * 3
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
// Start cracking effect animation
startCrackingEffect(candy);
}
});
// Show recreation notification
var recreationText = new Text2('TIMELESS KARADENIZ REBORN!', {
size: 80,
fill: '#FF4500'
});
recreationText.anchor.set(0.5, 0.5);
recreationText.x = 1024;
recreationText.y = 1200;
recreationText.alpha = 0;
game.addChild(recreationText);
tween(recreationText, {
alpha: 1,
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 600,
easing: tween.bounceOut,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(recreationText, {
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
if (recreationText.parent) {
recreationText.parent.removeChild(recreationText);
}
}
});
}, 2000);
}
});
// Add bonus for recreation
score += 5000;
gold += 2500;
updateUI();
LK.getSound('powerup').play();
LK.effects.flashScreen(0xFF4500, 800);
}
}
function startLevel7Victory() {
// Stop all processing
isProcessing = true;
// Disable all game controls permanently
gameState = 'victory';
// Hide combo text during victory sequence
tween(comboText, {
alpha: 0
}, {
duration: 300,
easing: tween.easeOut
});
// Stop music
LK.stopMusic();
// Start peaceful music
LK.playMusic('7week3days', {
fade: {
start: 0,
end: 0.3,
duration: 2000
}
});
// Make 99% of stars start sliding
makeStarsSlide();
// Start exploding all 8x8 candies during camera movement
explodeAllCandiesDuringVictory();
// Animate candy table moving up towards sky
tween(gameContainer, {
y: -2000,
// Move game container up and out of view
alpha: 0.8
}, {
duration: 4000,
easing: tween.easeOut,
onFinish: function onFinish() {
// Hide game container completely
gameContainer.alpha = 0;
// Show "KAZANDINIZ" text after table disappears
showVictoryText();
}
});
// Create sky background effect
createSkyBackground();
}
function createSkyBackground() {
// Change game background to sky color
game.setBackgroundColor(0x87CEEB); // Sky blue
}
function showVictoryText() {
// Create "KAZANDINIZ" text
var victoryText = new Text2('KAZANDINIZ', {
size: 200,
fill: '#FFD700'
});
victoryText.anchor.set(0.5, 0.5);
victoryText.x = 1024;
victoryText.y = 1366;
victoryText.alpha = 0;
victoryText.scaleX = 0.3;
victoryText.scaleY = 0.3;
game.addChild(victoryText);
// Animate victory text appearing
tween(victoryText, {
alpha: 1,
scaleX: 1.5,
scaleY: 1.5,
rotation: 0.1
}, {
duration: 1500,
easing: tween.bounceOut,
onFinish: function onFinish() {
// Wait 2 seconds then show congratulations
LK.setTimeout(function () {
showCongratulationsText(victoryText);
}, 2000);
}
});
}
function showCongratulationsText(victoryText) {
// Fade out victory text
tween(victoryText, {
alpha: 0,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 800,
easing: tween.easeIn,
onFinish: function onFinish() {
if (victoryText.parent) victoryText.parent.removeChild(victoryText);
}
});
// Create "Gerçekten tebrik ederim" text
var congratsText = new Text2('Gerçekten tebrik ederim', {
size: 120,
fill: '#FFFFFF'
});
congratsText.anchor.set(0.5, 0.5);
congratsText.x = 1024;
congratsText.y = 1366;
congratsText.alpha = 0;
game.addChild(congratsText);
// Animate congratulations text
tween(congratsText, {
alpha: 1,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
// Wait then show credits
LK.setTimeout(function () {
showCreditsSequence(congratsText);
}, 2000);
}
});
}
function showCreditsSequence(congratsText) {
// Fade out congratulations text
tween(congratsText, {
alpha: 0,
y: congratsText.y - 200
}, {
duration: 800,
easing: tween.easeIn,
onFinish: function onFinish() {
if (congratsText.parent) congratsText.parent.removeChild(congratsText);
}
});
// Create credits text "yapımcılar TIKLA SUNUCUSU"
var creditsText = new Text2('yapımcılar TIKLA SUNUCUSU', {
size: 80,
fill: '#FFD700'
});
creditsText.anchor.set(0.5, 0.5);
creditsText.x = 1024;
creditsText.y = 2800; // Start from bottom
creditsText.alpha = 1;
game.addChild(creditsText);
// Animate credits scrolling slowly upward
tween(creditsText, {
y: -200 // Move to top and beyond
}, {
duration: 8000,
easing: tween.linear,
onFinish: function onFinish() {
if (creditsText.parent) creditsText.parent.removeChild(creditsText);
// Show thank you message
showThankYouMessage();
}
});
}
function showThankYouMessage() {
// Create "oynadığınız için teşekkürler" text
var thankYouText = new Text2('oynadığınız için teşekkürler', {
size: 100,
fill: '#FFFFFF'
});
thankYouText.anchor.set(0.5, 0.5);
thankYouText.x = 1024;
thankYouText.y = 1366;
thankYouText.alpha = 0;
game.addChild(thankYouText);
// Animate thank you text
tween(thankYouText, {
alpha: 1,
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 1200,
easing: tween.easeOut,
onFinish: function onFinish() {
// Wait then create supernova from sky
LK.setTimeout(function () {
createSkySupernova(thankYouText);
}, 3000);
}
});
}
function createSkySupernova(thankYouText) {
// Create supernova in the sky
var skySupernova = LK.getAsset('supernova', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.1,
scaleY: 0.1,
x: 1024,
y: 400,
// Top part of sky
alpha: 0
});
game.addChild(skySupernova);
// Animate supernova explosion
tween(skySupernova, {
alpha: 1,
scaleX: 8.0,
scaleY: 8.0,
tint: 0xFFFFFF,
rotation: Math.PI * 8
}, {
duration: 3000,
easing: tween.easeOut,
onFinish: function onFinish() {
// Create massive screen flash
LK.effects.flashScreen(0xFFFFFF, 2000);
// Win the game
LK.setTimeout(function () {
LK.showYouWin();
}, 1000);
}
});
// Fade out thank you text during supernova
tween(thankYouText, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 2000,
easing: tween.easeIn,
onFinish: function onFinish() {
if (thankYouText.parent) thankYouText.parent.removeChild(thankYouText);
}
});
}
function turnAllCandiesPurple(warlekCandy) {
// Turn all candies on the grid purple with expanding wave effect
var centerRow = warlekCandy.row;
var centerCol = warlekCandy.col;
var maxDistance = Math.max(GRID_SIZE, GRID_SIZE);
for (var distance = 1; distance <= maxDistance; distance++) {
(function (dist) {
LK.setTimeout(function () {
// Collect all candies at this distance
var candiesAtDistance = [];
for (var r = 0; r < GRID_SIZE; r++) {
for (var c = 0; c < GRID_SIZE; c++) {
var actualDist = Math.max(Math.abs(r - centerRow), Math.abs(c - centerCol));
if (actualDist === dist && grid[r][c] && grid[r][c] !== warlekCandy) {
candiesAtDistance.push(grid[r][c]);
}
}
}
// Transform all candies at this distance to purple
for (var i = 0; i < candiesAtDistance.length; i++) {
(function (targetCandy, index) {
if (targetCandy && targetCandy.parent) {
// Update candy type to purple
targetCandy.type = 'purple';
// Remove old graphics
targetCandy.removeChild(targetCandy.graphics);
// Create new purple graphics
targetCandy.graphics = targetCandy.attachAsset('purpleCandy', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
});
// Reset special properties
targetCandy.isSpecial = false;
targetCandy.specialType = null;
targetCandy.isTimeless = false;
// Add transformation effect
tween(targetCandy.graphics, {
scaleX: 1.3,
scaleY: 1.3,
tint: 0x9013fe
}, {
duration: 400,
easing: tween.bounceOut,
onFinish: function onFinish() {
tween(targetCandy.graphics, {
scaleX: 0.8,
scaleY: 0.8,
tint: 0xFFFFFF
}, {
duration: 300,
easing: tween.easeOut
});
}
});
}
})(candiesAtDistance[i], i);
}
}, dist * 150); // Stagger waves outward
})(distance);
}
}
function makeStarsSlide() {
// Make 99% of all stars start sliding continuously
if (starField && starField.children) {
for (var i = 0; i < starField.children.length; i++) {
var star = starField.children[i];
// 99% chance for each star to start sliding
if (Math.random() < 0.99) {
// Set sliding properties for continuous sliding
star.slideSpeed = Math.random() * 3 + 1; // Random slide speed
star.slideDirection = Math.random() * Math.PI * 2; // Random direction
star.isSliding = true; // Flag to indicate continuous sliding
// Start continuous sliding animation
var _slideStarContinuously = function slideStarContinuously(starToSlide) {
if (starToSlide && starToSlide.parent && starToSlide.isSliding && gameState === 'victory') {
// Move star in its sliding direction
starToSlide.x += Math.cos(starToSlide.slideDirection) * starToSlide.slideSpeed;
starToSlide.y += Math.sin(starToSlide.slideDirection) * starToSlide.slideSpeed;
// Wrap around screen edges
if (starToSlide.x < -50) starToSlide.x = 2098;
if (starToSlide.x > 2098) starToSlide.x = -50;
if (starToSlide.y < -50) starToSlide.y = 2782;
if (starToSlide.y > 2782) starToSlide.y = -50;
// Continue sliding
LK.setTimeout(function () {
_slideStarContinuously(starToSlide);
}, 16); // ~60fps sliding
}
};
_slideStarContinuously(star);
}
}
}
}
function explodeAllCandiesDuringVictory() {
// Create spectacular explosion effects for all candies in the 8x8 grid
var allCandies = [];
// Collect all candies from the 8x8 grid
for (var row = 0; row < GRID_SIZE; row++) {
for (var col = 0; col < GRID_SIZE; col++) {
if (grid[row][col] && grid[row][col].parent) {
// Calculate distance from center for wave explosion effect
var centerRow = GRID_SIZE / 2;
var centerCol = GRID_SIZE / 2;
var distance = Math.sqrt(Math.pow(row - centerRow, 2) + Math.pow(col - centerCol, 2));
allCandies.push({
candy: grid[row][col],
distance: distance,
row: row,
col: col
});
}
}
}
// Sort candies by distance from center for wave explosion effect
allCandies.sort(function (a, b) {
return a.distance - b.distance;
});
// Create expanding explosion waves from center outward
for (var i = 0; i < allCandies.length; i++) {
(function (candyData, index) {
var delay = candyData.distance * 150 + index * 20; // Stagger explosions based on distance and index
LK.setTimeout(function () {
var candy = candyData.candy;
if (candy && candy.parent) {
// Create spectacular explosion effect for each candy
tween(candy.graphics, {
scaleX: 2.5,
scaleY: 2.5,
tint: 0xFFD700,
rotation: candy.graphics.rotation + Math.PI * 4,
alpha: 0.8
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
// Final explosion burst
tween(candy, {
scaleX: 4.0,
scaleY: 4.0,
alpha: 0,
rotation: candy.rotation + Math.PI * 6
}, {
duration: 400,
easing: tween.easeIn,
onFinish: function onFinish() {
// Remove candy from grid and game
if (candy.parent) {
candy.parent.removeChild(candy);
}
grid[candyData.row][candyData.col] = null;
}
});
}
});
}
}, delay);
})(allCandies[i], i);
}
// Create massive screen flash effects during the explosion sequence
LK.setTimeout(function () {
LK.effects.flashScreen(0xFFD700, 1000);
}, 500);
LK.setTimeout(function () {
LK.effects.flashScreen(0xFFFFFF, 1200);
}, 1500);
LK.setTimeout(function () {
LK.effects.flashScreen(0xFFD700, 800);
}, 2800);
}
function showPlayerNameInput() {
// Create name input dialog background
var inputBg = LK.getAsset('progressBarBg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 3.0,
scaleY: 4.0
});
inputBg.x = 1024;
inputBg.y = 1366;
game.addChild(inputBg);
// Create title text
var titleText = new Text2('Adınızı Girin:', {
size: 80,
fill: '#FFD700'
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 1200;
game.addChild(titleText);
// Create instruction text
var instructionText = new Text2('Lütfen 3-15 karakter arası bir ad girin', {
size: 50,
fill: '#FFFFFF'
});
instructionText.anchor.set(0.5, 0.5);
instructionText.x = 1024;
instructionText.y = 1300;
game.addChild(instructionText);
// Create sample names for selection
var sampleNames = ['Oyuncu', 'Şeker Avcısı', 'Kombo Ustası', 'Patlat Kralı', 'Candy Master'];
var selectedNameIndex = 0;
var currentName = sampleNames[0];
// Create display text for selected name
var nameDisplayText = new Text2(currentName, {
size: 70,
fill: '#00FF00'
});
nameDisplayText.anchor.set(0.5, 0.5);
nameDisplayText.x = 1024;
nameDisplayText.y = 1400;
game.addChild(nameDisplayText);
// Create navigation buttons
var prevButton = LK.getAsset('progressBarBg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.0,
scaleY: 1.0
});
prevButton.x = 800;
prevButton.y = 1400;
game.addChild(prevButton);
var prevButtonText = new Text2('<', {
size: 60,
fill: '#FFFFFF'
});
prevButtonText.anchor.set(0.5, 0.5);
prevButtonText.x = 800;
prevButtonText.y = 1400;
game.addChild(prevButtonText);
var nextButton = LK.getAsset('progressBarBg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.0,
scaleY: 1.0
});
nextButton.x = 1248;
nextButton.y = 1400;
game.addChild(nextButton);
var nextButtonText = new Text2('>', {
size: 60,
fill: '#FFFFFF'
});
nextButtonText.anchor.set(0.5, 0.5);
nextButtonText.x = 1248;
nextButtonText.y = 1400;
game.addChild(nextButtonText);
// Create confirm button
var confirmButton = LK.getAsset('progressBarBg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.0,
scaleY: 1.5
});
confirmButton.x = 1024;
confirmButton.y = 1550;
game.addChild(confirmButton);
var confirmButtonText = new Text2('ONAYLA', {
size: 60,
fill: '#FFFFFF'
});
confirmButtonText.anchor.set(0.5, 0.5);
confirmButtonText.x = 1024;
confirmButtonText.y = 1550;
game.addChild(confirmButtonText);
// Store references for cleanup
var inputElements = [inputBg, titleText, instructionText, nameDisplayText, prevButton, prevButtonText, nextButton, nextButtonText, confirmButton, confirmButtonText];
// Handle input navigation
function handleNameInputClick(x, y) {
// Check prev button
var dx = x - prevButton.x;
var dy = y - prevButton.y;
if (Math.sqrt(dx * dx + dy * dy) < 100) {
selectedNameIndex = (selectedNameIndex - 1 + sampleNames.length) % sampleNames.length;
currentName = sampleNames[selectedNameIndex];
nameDisplayText.setText(currentName);
return;
}
// Check next button
dx = x - nextButton.x;
dy = y - nextButton.y;
if (Math.sqrt(dx * dx + dy * dy) < 100) {
selectedNameIndex = (selectedNameIndex + 1) % sampleNames.length;
currentName = sampleNames[selectedNameIndex];
nameDisplayText.setText(currentName);
return;
}
// Check confirm button
dx = x - confirmButton.x;
dy = y - confirmButton.y;
if (Math.sqrt(dx * dx + dy * dy) < 150) {
// Validate name
if (currentName.length >= 3 && currentName.length <= 15) {
// Save player name
storage.currentPlayerName = currentName;
// Clean up input elements
for (var i = 0; i < inputElements.length; i++) {
if (inputElements[i].parent) {
inputElements[i].parent.removeChild(inputElements[i]);
}
}
// Remove input handler
game.nameInputHandler = null;
// Start the game
startGame();
} else {
// Show validation error
var errorText = new Text2('Ad 3-15 karakter arası olmalı!', {
size: 50,
fill: '#FF0000'
});
errorText.anchor.set(0.5, 0.5);
errorText.x = 1024;
errorText.y = 1650;
errorText.alpha = 0;
game.addChild(errorText);
tween(errorText, {
alpha: 1
}, {
duration: 300,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(errorText, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
if (errorText.parent) {
errorText.parent.removeChild(errorText);
}
}
});
}, 2000);
}
});
}
return;
}
}
// Set up input handler
game.nameInputHandler = handleNameInputClick;
}
function addPlayerToList(playerName) {
// Get existing player names
var playerNames = storage.playerNames || [];
// Check if player already exists
var exists = false;
for (var i = 0; i < playerNames.length; i++) {
if (playerNames[i] === playerName) {
exists = true;
break;
}
}
// Add player if not exists - this ensures all players are tracked
if (!exists) {
playerNames.push(playerName);
// Increase limit to show more players publicly (last 20 players)
if (playerNames.length > 20) {
playerNames = playerNames.slice(-20);
}
// Store updated player list - this is visible to all players
storage.playerNames = playerNames;
}
}