User prompt
Oynu oynayan tüm oyuncuların ismi herkese gozukcek şekilde listeleniyor ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
İstatistiklerde oynu oynayan herkesin adı gözükecek ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
yeni oyuna basılınca 1. seviye 00000000 score olucak ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
yeni oyuna basıldığında score 0 olur ve ana menude kalır ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
yeni oyuna basınca mevcut score sıfırlanır ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
ana menuye yeni oyun seçeneği ekle kayıtlardan tekrar save yüklenebilir kayıtlar sıfırlanmicak ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
son final sahnesinde ekrandaki kombo yazısını kaldır
User prompt
Please fix the bug: 'Error: Invalid value. Only literals or 1-level deep objects/arrays containing literals are allowed.' in or related to this line: 'storage['saveSlot' + (slotIndex + 1)] = saveData;' Line Number: 5526 ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
ana menuye kayıtlar sekmesi ekle 4 boş kayıt simgesinden birine basara scoreyi savelenir 4 farklı bölmeye save alınabilir ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Ana menüye istatikler seçeneği ekle tüm istatikleri gösterecek ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
oyun bittiğinden ihtibaren tüm konturoller geçersiz syaılır ve oyuna müdale edilemez ve %99 yıldı kaymaya başlar ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
bide kamera yukarıya doğru giderken tüm 8x8 alan patlayarak yok olsun ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
oyunda 7. seviyeye ulaşınc aekran şeker tablosundan gök yüüzne doğru gitsin sakin müzik eşliğinde tablo kadrajtan çksın kazandınız yazsın 2 saniye sonra gerçekten tebrik ederim yazsın sonra yapımıclar TIKLA SUNUCUSU yavaşça aşşağa doğru aksın ve şu yazı görünsün oynadığınız için teşekküler yazsın ve göjk yüzünden bir süpernowa kaysın ve oyun kaznaılsın ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Fpsnup hataları düzelt arka plana şeker düşmesin
User prompt
Zamansız kara deliğin işlevini değiştiriyorum ↪💡 Consider importing and using the following plugins: @upit/tween.v1
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
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;
}
} ===================================================================
--- original.js
+++ change.js
@@ -1363,15 +1363,16 @@
playerNamesTitle.y = yPosition + spacing * 5.5;
statisticsMenuContainer.addChild(playerNamesTitle);
// Get all player names from storage (stored as an array)
var playerNames = storage.playerNames || [];
- var displayText = playerNames.length > 0 ? playerNames.join(', ') : 'Henüz oyuncu yok';
- // Limit text length to prevent overflow
- if (displayText.length > 50) {
- displayText = displayText.substring(0, 50) + '...';
+ // 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: 50,
+ size: 45,
fill: '#FFFFFF'
});
playerNamesText.anchor.set(0.5, 0.5);
playerNamesText.x = 1024;
@@ -7194,14 +7195,15 @@
exists = true;
break;
}
}
- // Add player if not exists
+ // Add player if not exists - this ensures all players are tracked
if (!exists) {
playerNames.push(playerName);
- // Limit to last 10 players to prevent storage overflow
- if (playerNames.length > 10) {
- playerNames = playerNames.slice(-10);
+ // 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;
}
}
\ No newline at end of file