User prompt
Donan kristal patlayabilir şartlar sağlanıyorsa. Mesela joker kristalini dondurdum. Bir sonraki tur 9 mavi kristal geldi. Totalde 10 edeceği için patlasım.
User prompt
Donan kristal eğer şartlar sağlanırsa patlayabilir
User prompt
Yahu niye ekrandan siliyorsun sonan kristali. Bir tur bekle sonra sil
User prompt
Düzelt o zaman
User prompt
Arkadaşım. Sadece bir tur donacak. İkinci tur donmayı kaldır. Ayrıca patlayabilir donan kristal
User prompt
3 freeze hakkı var. Bir tur kullandıktan sonra seçimi kaldır ve hakkı düşür
User prompt
Ya hayır. Freeze tuşuna bastıktan sonra tıkladığım kristal ekranda sabit duracak.
User prompt
Ekranda sabit duracak.
User prompt
Freeze bastıktan sonra tıkladığım kristal değişmeyecek.
User prompt
Freeze tuşuna bastıktan sonra hangi kristale tıklarsam o kristal donacak. Spine basıldığında tüm kristaller değişirken o kristal değişmeyecek
User prompt
Freeze çalışmıyor. Düzeltir misin. Anlattım nasıl çalışması gerektiğini yüZ defa
User prompt
Freeze tuşu çalışmıyor. Tıklanan bir kristali sabit tutması lazım diğer tur için.
User prompt
Freeze tuşuna bastıktan sonra hangi kristale tıklarsam o kristalin etrafında kare çerçeve oluşsun ve spin tuşuna basıldığında bir tur değişmesin.
User prompt
Freeze tuşu oyun içinde üç defa kullanılabilir ve hangi kristalin üzerine dokunursa oyuncu o kristal spin tuşuna basıldığında bir sonraki tur yerinde kalır ve diğer kristaller değişir sadece
User prompt
Bomb tuşu patlattıktan sonra yukarıdan yeni gelen kristallerin boşluğu doldurması lazım
User prompt
Bomb, freeze ve swap tuşları çalışmıyor. Bomb tuşuna basıldığında hangi kristale tıklarsam etrafındaki kristallerin patlaması gerekiyor. Bu hak oyun içinde sadece bir defa veriliyor
User prompt
Please fix the bug: 'storage.set is not a function' in or related to this line: 'storage.set("dailyMissions", {' Line Number: 197 ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Please fix the bug: 'storage.get is not a function' in or related to this line: 'var saved = storage.get("dailyMissions");' Line Number: 175 ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Please fix the bug: 'storage is not defined' in or related to this line: 'var saved = storage.get("dailyMissions");' Line Number: 174
User prompt
Her gün 3 rastgele görev oluştur. Görevler örnek olarak: 10 kırmızı kristal patlat 5 joker kristal patlat Görevler tamamlanınca oyuncuya ödül ver.
User prompt
Oyuncu skoruna göre seviye atlayacak. Her 1000 puanda bir seviye artsın ve jokerProbability azalsın.
User prompt
Please fix the bug: 'Cannot read properties of undefined (reading '0')' in or related to this line: 'var crystal = board[r][c];' Line Number: 659
User prompt
"Oyuncuya 3 farklı özel güç butonu ekle: bomb: seçilen kristal ve çevresini yok eder. swap: seçilen iki kristalin yerini değiştirir. freeze: bir kristalin joker olmasını engeller." ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Bir hamlede birden fazla zincirleme patlama (cascade) oluşuyorsa, her ek zincir için skoru comboMultiplier çarpanı ile arttır. İlk patlama x1, ikinci x2, üçüncü x3 vb. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
ya da yanıp sönmeyi sil. patlamadan önce iki saniye titremeye başlasınlar ve sonra patlasınlar.
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Crystal class var Crystal = Container.expand(function () { var self = Container.call(this); // type: 'blue', 'yellow', 'red', 'purple', 'white', 'joker' self.type = 'blue'; self.row = 0; self.col = 0; self.popping = false; // Attach correct asset function setAsset() { if (self.asset) self.removeChild(self.asset); var assetId = 'crystal_' + self.type; self.asset = self.attachAsset(assetId, { anchorX: 0.5, anchorY: 0.5 }); } self.setType = function (type) { self.type = type; setAsset(); }; // Animate pop self.pop = function (_onFinish) { if (self.popping) return; self.popping = true; tween(self, { scaleX: 1.4, scaleY: 1.4, alpha: 0 }, { duration: 350, easing: tween.easeOut, onFinish: function onFinish() { if (_onFinish) _onFinish(); } }); LK.getSound('crystal_pop').play(); }; // Reset visual state self.resetVisual = function () { self.scaleX = 1; self.scaleY = 1; self.alpha = 1; self.popping = false; // Remove freeze frame if present if (self.freezeFrame) { self.removeChild(self.freezeFrame); self.freezeFrame = null; } }; // Add or remove freeze frame self.setFreezeFrame = function (show) { if (show) { if (!self.freezeFrame) { // Create a square frame using a box shape, slightly larger than the crystal var frame = LK.getAsset('spin_btn_shape', { anchorX: 0.5, anchorY: 0.5 }); frame.width = self.asset.width * 1.18; frame.height = self.asset.height * 1.18; frame.alpha = 0.7; frame.tint = 0x00e6b8; frame.zIndex = -1; self.addChildAt(frame, 0); self.freezeFrame = frame; } if (self.freezeFrame) self.freezeFrame.visible = true; } else { if (self.freezeFrame) { self.removeChild(self.freezeFrame); self.freezeFrame = null; } } }; setAsset(); return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x181c2c }); /**** * Game Code ****/ // --- Game Constants --- // Crystal shapes (box for simplicity, different colors for each type) // Sound effects (placeholders, actual sound assets will be loaded by LK) var BOARD_COLS = 4; var BOARD_ROWS = 6; var CRYSTAL_SIZE = 300; // px var CRYSTAL_SPACING = 24; // px var BOARD_WIDTH = BOARD_COLS * CRYSTAL_SIZE + (BOARD_COLS - 1) * CRYSTAL_SPACING; var BOARD_HEIGHT = BOARD_ROWS * CRYSTAL_SIZE + (BOARD_ROWS - 1) * CRYSTAL_SPACING; var BOARD_X = (2048 - BOARD_WIDTH) / 2; var BOARD_Y = (2732 - BOARD_HEIGHT) / 2 - 180; // move board up to make space for spin button var CRYSTAL_TYPES = ['blue', 'yellow', 'red', 'purple', 'white', 'joker']; var CRYSTAL_COLORS = { blue: 0x3a8ee6, yellow: 0xf7e14a, red: 0xe64a3a, purple: 0xb44ae6, white: 0xffffff, joker: 0x00e6b8 }; // Score values per crystal type var CRYSTAL_SCORES = { blue: 10, yellow: 12, red: 14, purple: 16, white: 18, joker: 25 }; // --- Game State --- var board = []; // 2D array [row][col] of Crystal or null var poppingCrystals = []; // Crystals currently popping var isCascading = false; var scoreTxt; var cascadeTimeout = null; // --- Level and Joker Probability State --- var level = 1; var jokerProbability = 0.10; // Start at 10% // --- UI: Score --- scoreTxt = new Text2('0', { size: 120, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // --- Board Initialization --- function createEmptyBoard() { board = []; for (var row = 0; row < BOARD_ROWS; row++) { var rowArr = []; for (var col = 0; col < BOARD_COLS; col++) { rowArr.push(null); } board.push(rowArr); } } function randomCrystalType() { // Use current jokerProbability (decreases as level increases) var r = Math.random(); if (r < jokerProbability) return 'joker'; var idx = Math.floor(Math.random() * 5); return CRYSTAL_TYPES[idx]; } function spawnCrystal(row, col, type) { var crystal = new Crystal(); crystal.setType(type); crystal.row = row; crystal.col = col; // Position var x = BOARD_X + col * (CRYSTAL_SIZE + CRYSTAL_SPACING) + CRYSTAL_SIZE / 2; var y = BOARD_Y + row * (CRYSTAL_SIZE + CRYSTAL_SPACING) + CRYSTAL_SIZE / 2; crystal.x = x; crystal.y = y; crystal.resetVisual(); game.addChild(crystal); // Make crystal fixed: prevent any movement or change crystal.interactive = false; crystal.buttonMode = false; crystal.down = function () {}; crystal.pop = function () {}; crystal.setType = function (type) {}; crystal.resetVisual = function () {}; crystal.setFreezeFrame = function () {}; return crystal; } function fillBoardRandom() { for (var row = 0; row < BOARD_ROWS; row++) { for (var col = 0; col < BOARD_COLS; col++) { var type = randomCrystalType(); var crystal = spawnCrystal(row, col, type); board[row][col] = crystal; } } refreshCrystalInteractivity(); } // --- Board Utility --- function getNeighbors(row, col) { // 4-directional neighbors var n = []; if (row > 0) n.push([row - 1, col]); if (row < BOARD_ROWS - 1) n.push([row + 1, col]); if (col > 0) n.push([row, col - 1]); if (col < BOARD_COLS - 1) n.push([row, col + 1]); return n; } // --- Find Groups for Popping --- function findPopGroups() { // Returns: [{type, crystals: [Crystal, ...], jokerCount: n}] var groups = []; // Count all crystals by type (excluding jokers) var typeCounts = {}; var typeCrystals = {}; var jokerCrystals = []; for (var i = 0; i < CRYSTAL_TYPES.length; i++) { var t = CRYSTAL_TYPES[i]; if (t !== 'joker') { typeCounts[t] = 0; typeCrystals[t] = []; } } for (var row = 0; row < BOARD_ROWS; row++) { for (var col = 0; col < BOARD_COLS; col++) { var crystal = board[row][col]; if (!crystal) continue; if (crystal.type === 'joker') { // If frozen, do not count as joker if (!crystal.frozen) { jokerCrystals.push(crystal); } } else { typeCounts[crystal.type]++; typeCrystals[crystal.type].push(crystal); } } } // For each color, see if color+joker >= 10, if so, pop all of that color and enough jokers for (var t in typeCounts) { var total = typeCounts[t] + jokerCrystals.length; if (total >= 10) { // Add all of this color var groupCrystals = []; for (var i = 0; i < typeCrystals[t].length; i++) { groupCrystals.push(typeCrystals[t][i]); } // Add jokers for (var j = 0; j < jokerCrystals.length; j++) { groupCrystals.push(jokerCrystals[j]); } groups.push({ type: t, crystals: groupCrystals, jokerCount: jokerCrystals.length }); } } return groups; } // --- Pop Groups --- function popGroups(groups, onFinish) { if (groups.length === 0) { if (onFinish) onFinish(); return; } isCascading = true; poppingCrystals = []; var popped = {}; // --- Combo Multiplier Logic --- if (typeof comboMultiplier === "undefined") { comboMultiplier = 1; } if (typeof lastCascadeMoveId === "undefined") { lastCascadeMoveId = 0; } if (typeof currentCascadeMoveId === "undefined") { currentCascadeMoveId = 0; } // If this is a new cascade move, reset comboMultiplier if (typeof cascadeMoveActive === "undefined" || !cascadeMoveActive) { comboMultiplier = 1; currentCascadeMoveId = Date.now(); lastCascadeMoveId = currentCascadeMoveId; cascadeMoveActive = true; } else { // If still in the same move, increment comboMultiplier if (currentCascadeMoveId === lastCascadeMoveId) { comboMultiplier++; } else { comboMultiplier = 1; currentCascadeMoveId = Date.now(); lastCascadeMoveId = currentCascadeMoveId; } } // Mark all crystals to pop (avoid double pop) for (var g = 0; g < groups.length; g++) { var group = groups[g]; for (var i = 0; i < group.crystals.length; i++) { var c = group.crystals[i]; var key = c.row + ',' + c.col; if (!popped[key]) { popped[key] = true; poppingCrystals.push(c); } } } // Animate pop with 2s shake before popping var popCount = poppingCrystals.length; var finished = 0; for (var i = 0; i < poppingCrystals.length; i++) { var c = poppingCrystals[i]; (function (crystal) { // Save original position var origX = crystal.x; var origY = crystal.y; var shakeDuration = 2000; var shakeInterval = 30; var elapsed = 0; var shakeTimer = null; function startShake() { shakeTimer = LK.setInterval(function () { // Random shake offset, smaller amplitude for subtle effect var dx = (Math.random() - 0.5) * 24; var dy = (Math.random() - 0.5) * 24; crystal.x = origX + dx; crystal.y = origY + dy; elapsed += shakeInterval; if (elapsed >= shakeDuration) { // End shake, restore position LK.clearInterval(shakeTimer); crystal.x = origX; crystal.y = origY; // Now pop crystal.pop(function () { finished++; if (finished === popCount) { // Remove from board for (var j = 0; j < poppingCrystals.length; j++) { var pc = poppingCrystals[j]; if (board[pc.row][pc.col] === pc) { board[pc.row][pc.col] = null; pc.destroy(); } } poppingCrystals = []; if (onFinish) onFinish(); } }); } }, shakeInterval); } startShake(); })(c); } // Score with combo multiplier for (var g = 0; g < groups.length; g++) { var group = groups[g]; var baseScore = 0; for (var i = 0; i < group.crystals.length; i++) { var c = group.crystals[i]; var t = c.type === 'joker' ? group.type : c.type; baseScore += CRYSTAL_SCORES[t]; } LK.setScore(LK.getScore() + baseScore * comboMultiplier); } scoreTxt.setText(LK.getScore()); LK.getSound('cascade').play(); LK.effects.flashObject(scoreTxt, 0xffff00, 400); // --- Level Up Logic --- var newLevel = Math.floor(LK.getScore() / 1000) + 1; if (newLevel > level) { level = newLevel; // Decrease jokerProbability by 1% per level up, but not below 1% jokerProbability = Math.max(0.01, 0.10 - (level - 1) * 0.01); // Optional: flash score text or give feedback for level up LK.effects.flashObject(scoreTxt, 0x00ff00, 600); } } // --- Cascade: Drop Crystals Down and Fill --- function cascadeBoard(onFinish) { // For each column, drop crystals down to fill empty spaces var changed = false; for (var col = 0; col < BOARD_COLS; col++) { var emptyRows = []; for (var row = BOARD_ROWS - 1; row >= 0; row--) { if (!board[row][col]) { emptyRows.push(row); } else if (emptyRows.length > 0) { // Move crystal down var targetRow = emptyRows.shift(); var crystal = board[row][col]; board[targetRow][col] = crystal; board[row][col] = null; crystal.row = targetRow; crystal.col = col; // Animate drop var newY = BOARD_Y + targetRow * (CRYSTAL_SIZE + CRYSTAL_SPACING) + CRYSTAL_SIZE / 2; tween(crystal, { y: newY }, { duration: 220, easing: tween.cubicOut }); emptyRows.push(row); changed = true; } } } // Fill empty spaces at the top for (var col = 0; col < BOARD_COLS; col++) { for (var row = 0; row < BOARD_ROWS; row++) { if (!board[row][col]) { var type = randomCrystalType(); var crystal = spawnCrystal(row, col, type); board[row][col] = crystal; // Drop from above var startY = BOARD_Y - CRYSTAL_SIZE; crystal.y = startY; var targetY = BOARD_Y + row * (CRYSTAL_SIZE + CRYSTAL_SPACING) + CRYSTAL_SIZE / 2; tween(crystal, { y: targetY }, { duration: 220, easing: tween.cubicOut }); changed = true; } } } // Wait for animation, then call onFinish LK.setTimeout(function () { refreshCrystalInteractivity(); if (onFinish) onFinish(); }, 250); } // --- Main Game Loop: Cascade, Pop, Repeat --- function startCascadeLoop() { if (cascadeTimeout) { LK.clearTimeout(cascadeTimeout); cascadeTimeout = null; } var groups = findPopGroups(); if (groups.length === 0) { isCascading = false; return; } popGroups(groups, function () { cascadeBoard(function () { // Chain reaction! cascadeTimeout = LK.setTimeout(function () { startCascadeLoop(); }, 120); }); }); } // --- Start New Game --- function startGame() { LK.setScore(2000); scoreTxt.setText('2000'); // Reset combo multiplier state for new game comboMultiplier = 1; cascadeMoveActive = false; // Reset bomb usage for new game bombUsed = false; // Reset freeze usage for new game freezeUsedCount = 0; freezeBtnBg.alpha = 1; freezeBtnContainer.interactive = true; freezeBtnContainer.buttonMode = true; // Reset level and jokerProbability level = 1; jokerProbability = 0.10; // Remove all crystals for (var row = 0; row < BOARD_ROWS; row++) { for (var col = 0; col < BOARD_COLS; col++) { if (board[row] && board[row][col]) { board[row][col].frozen = false; board[row][col].alpha = 1; // Remove freeze frame if present if (typeof board[row][col].setFreezeFrame === "function") { board[row][col].setFreezeFrame(false); } board[row][col].destroy(); } } } createEmptyBoard(); fillBoardRandom(); refreshCrystalInteractivity(); LK.setTimeout(function () { startCascadeLoop(); }, 400); } // --- Karıştır Button --- var shuffleBtn = new Text2('Karıştır', { size: 110, fill: 0x00E6B8, font: "Arial Black" }); shuffleBtn.anchor.set(0.5, 1); shuffleBtn.x = LK.gui.width / 2; shuffleBtn.y = LK.gui.height - 60 - 140; // Move up to make space for spin button shuffleBtn.interactive = true; shuffleBtn.buttonMode = true; LK.gui.bottom.addChild(shuffleBtn); function reshuffleBoardWithFall() { if (isCascading) return; // Reset combo multiplier state for new move comboMultiplier = 1; cascadeMoveActive = false; // Remove all crystals for (var row = 0; row < BOARD_ROWS; row++) { for (var col = 0; col < BOARD_COLS; col++) { if (board[row][col]) { // Only destroy if not a frozen joker if (!(board[row][col].type === "joker" && board[row][col].frozen)) { board[row][col].frozen = false; board[row][col].alpha = 1; // Remove freeze frame if present if (typeof board[row][col].setFreezeFrame === "function") { board[row][col].setFreezeFrame(false); } board[row][col].destroy(); board[row][col] = null; } } } } // Do not recreate the board, just refill non-frozen spots // Fill board with new crystals, but spawn them above and animate falling for (var row = 0; row < BOARD_ROWS; row++) { for (var col = 0; col < BOARD_COLS; col++) { // If the cell is empty, fill with a new crystal if (!board[row][col]) { var type = randomCrystalType(); var crystal = spawnCrystal(row, col, type); board[row][col] = crystal; // Start above the board var targetY = crystal.y; crystal.y = BOARD_Y - CRYSTAL_SIZE * 2; tween(crystal, { y: targetY }, { duration: 3000, easing: tween.cubicOut }); } else if (board[row][col].type === "joker" && board[row][col].frozen) { // Animate frozen joker to its own position for effect var targetY = BOARD_Y + row * (CRYSTAL_SIZE + CRYSTAL_SPACING) + CRYSTAL_SIZE / 2; tween(board[row][col], { y: targetY }, { duration: 3000, easing: tween.cubicOut }); // Ensure freeze frame is visible if (typeof board[row][col].setFreezeFrame === "function") { board[row][col].setFreezeFrame(true); } board[row][col].alpha = 0.5; } else if (!(board[row][col].type === "joker" && board[row][col].frozen)) { // For all non-frozen crystals (including non-jokers and non-frozen jokers), replace with a new random crystal var prev = board[row][col]; // If this is a frozen joker, skip replacing it if (prev.type === "joker" && prev.frozen) { // Animate frozen joker to its own position for effect var targetY = BOARD_Y + row * (CRYSTAL_SIZE + CRYSTAL_SPACING) + CRYSTAL_SIZE / 2; tween(prev, { y: targetY }, { duration: 3000, easing: tween.cubicOut }); // Ensure freeze frame is visible if (typeof prev.setFreezeFrame === "function") { prev.setFreezeFrame(true); } prev.alpha = 0.5; continue; } var type = randomCrystalType(); // Remove old crystal prev.destroy(); // Spawn new crystal var crystal = spawnCrystal(row, col, type); board[row][col] = crystal; // Start above the board var targetY = crystal.y; crystal.y = BOARD_Y - CRYSTAL_SIZE * 2; tween(crystal, { y: targetY }, { duration: 3000, easing: tween.cubicOut }); } } } refreshCrystalInteractivity(); LK.setTimeout(function () { startCascadeLoop(); }, 3100); } // Button event shuffleBtn.down = function (x, y, obj) { reshuffleBoardWithFall(); }; // --- Spin Button (visible, below crystals) --- var spinBtnContainer = new Container(); var spinBtnBg = LK.getAsset('spin_btn_shape', { anchorX: 0.5, anchorY: 0.5 }); spinBtnContainer.addChild(spinBtnBg); var spinBtnText = new Text2('Spin', { size: 90, fill: 0xffffff, font: "Arial Black" }); spinBtnText.anchor.set(0.5, 0.5); spinBtnText.x = 0; spinBtnText.y = 0; spinBtnContainer.addChild(spinBtnText); // Position: just below the board, centered horizontally spinBtnContainer.x = 2048 / 2; spinBtnContainer.y = BOARD_Y + BOARD_HEIGHT + 100 + spinBtnBg.height / 2; // Make interactive spinBtnContainer.interactive = true; spinBtnContainer.buttonMode = true; spinBtnContainer.down = function (x, y, obj) { if (isCascading) return; var currentCoins = LK.getScore(); if (currentCoins < 100) { // Not enough coins, flash red for feedback LK.effects.flashObject(spinBtnBg, 0xff0000, 300); return; } // Reset combo multiplier state for new move comboMultiplier = 1; cascadeMoveActive = false; LK.setScore(currentCoins - 100); scoreTxt.setText(LK.getScore()); reshuffleBoardWithFall(); // Optional: flash the button for feedback LK.effects.flashObject(spinBtnBg, 0xffffff, 200); }; // Add to game scene (not GUI, so it stays relative to board) game.addChild(spinBtnContainer); // --- Special Power Buttons --- // State for power selection var powerMode = null; // "bomb", "swap", "freeze" or null var swapFirstCrystal = null; // Helper to clear power mode UI state function clearPowerMode() { powerMode = null; swapFirstCrystal = null; bombBtnBg.alpha = 1; swapBtnBg.alpha = 1; freezeBtnBg.alpha = 1; } // --- Bomb Button --- var bombBtnContainer = new Container(); var bombBtnBg = LK.getAsset('spin_btn_shape', { anchorX: 0.5, anchorY: 0.5 }); bombBtnBg.tint = 0xff4444; bombBtnContainer.addChild(bombBtnBg); var bombBtnText = new Text2('Bomb', { size: 70, fill: 0xffffff, font: "Arial Black" }); bombBtnText.anchor.set(0.5, 0.5); bombBtnText.x = 0; bombBtnText.y = 0; bombBtnContainer.addChild(bombBtnText); bombBtnContainer.x = spinBtnContainer.x - 500; bombBtnContainer.y = spinBtnContainer.y; bombBtnContainer.interactive = true; bombBtnContainer.buttonMode = true; bombBtnContainer.down = function () { clearPowerMode(); powerMode = "bomb"; bombBtnBg.alpha = 0.7; }; // --- Swap Button --- var swapBtnContainer = new Container(); var swapBtnBg = LK.getAsset('spin_btn_shape', { anchorX: 0.5, anchorY: 0.5 }); swapBtnBg.tint = 0x44aaff; swapBtnContainer.addChild(swapBtnBg); var swapBtnText = new Text2('Swap', { size: 70, fill: 0xffffff, font: "Arial Black" }); swapBtnText.anchor.set(0.5, 0.5); swapBtnText.x = 0; swapBtnText.y = 0; swapBtnContainer.addChild(swapBtnText); swapBtnContainer.x = spinBtnContainer.x; swapBtnContainer.y = spinBtnContainer.y + 220; swapBtnContainer.interactive = true; swapBtnContainer.buttonMode = true; swapBtnContainer.down = function () { clearPowerMode(); powerMode = "swap"; swapBtnBg.alpha = 0.7; }; // --- Freeze Button --- var freezeBtnContainer = new Container(); var freezeBtnBg = LK.getAsset('spin_btn_shape', { anchorX: 0.5, anchorY: 0.5 }); freezeBtnBg.tint = 0x44ffd0; freezeBtnContainer.addChild(freezeBtnBg); var freezeBtnText = new Text2('Freeze', { size: 70, fill: 0x222222, font: "Arial Black" }); freezeBtnText.anchor.set(0.5, 0.5); freezeBtnText.x = 0; freezeBtnText.y = 0; freezeBtnContainer.addChild(freezeBtnText); freezeBtnContainer.x = spinBtnContainer.x + 500; freezeBtnContainer.y = spinBtnContainer.y; freezeBtnContainer.interactive = true; freezeBtnContainer.buttonMode = true; // Track freeze usage if (typeof freezeUsedCount === "undefined") { var freezeUsedCount = 0; } var freezeMaxCount = 3; freezeBtnContainer.down = function () { clearPowerMode(); if (freezeUsedCount >= freezeMaxCount) { // Visually disable freeze button if limit reached freezeBtnBg.alpha = 0.3; freezeBtnContainer.interactive = false; freezeBtnContainer.buttonMode = false; return; } powerMode = "freeze"; freezeBtnBg.alpha = 0.7; }; // Add to game game.addChild(bombBtnContainer); game.addChild(swapBtnContainer); game.addChild(freezeBtnContainer); // --- Power Button Crystal Selection Logic --- // Track bomb usage if (typeof bombUsed === "undefined") { var bombUsed = false; } // Helper to re-apply crystal interactivity for powers function applyPowerCrystalInteractivity() { for (var row = 0; row < BOARD_ROWS; row++) { if (!board[row]) continue; for (var col = 0; col < BOARD_COLS; col++) { (function (r, c) { if (!board[r]) return; var crystal = board[r][c]; if (!crystal) return; crystal.interactive = true; crystal.buttonMode = true; crystal.down = function () { if (isCascading) return; // Bomb: destroy selected and neighbors, only if not used yet if (powerMode === "bomb" && !bombUsed) { var finishBombPop = function finishBombPop() { clearPowerMode(); LK.setTimeout(function () { startCascadeLoop(); }, 400); }; bombUsed = true; var targets = [[r, c]]; var neighbors = getNeighbors(r, c); for (var i = 0; i < neighbors.length; i++) { var nr = neighbors[i][0], nc = neighbors[i][1]; if (board[nr][nc]) targets.push([nr, nc]); } var poppedCount = 0; var toPop = []; for (var i = 0; i < targets.length; i++) { var tr = targets[i][0], tc = targets[i][1]; if (board[tr][tc]) { toPop.push([tr, tc]); } } if (toPop.length === 0) { finishBombPop(); return; } var finished = 0; for (var i = 0; i < toPop.length; i++) { var tr = toPop[i][0], tc = toPop[i][1]; if (board[tr][tc]) { board[tr][tc].pop(function () { finished++; if (finished === toPop.length) { // Remove all popped for (var j = 0; j < toPop.length; j++) { var rr = toPop[j][0], cc = toPop[j][1]; if (board[rr][cc]) { board[rr][cc].destroy(); board[rr][cc] = null; } } // After bomb pop, trigger cascadeBoard to fill empty spaces cascadeBoard(function () { finishBombPop(); }); } }); } } // Visually disable bomb button bombBtnBg.alpha = 0.3; bombBtnContainer.interactive = false; bombBtnContainer.buttonMode = false; return; } // Swap: select two, then swap else if (powerMode === "swap") { if (!swapFirstCrystal) { swapFirstCrystal = { row: r, col: c }; tween(crystal, { scaleX: 1.2, scaleY: 1.2 }, { duration: 200, easing: tween.easeOut }); } else { var c1 = swapFirstCrystal; var c2 = { row: r, col: c }; if (c1.row === c2.row && c1.col === c2.col) { // Same crystal, ignore return; } // Swap types var tempType = board[c1.row][c1.col].type; board[c1.row][c1.col].setType(board[c2.row][c2.col].type); board[c2.row][c2.col].setType(tempType); // Animate swap var c1x = board[c1.row][c1.col].x, c1y = board[c1.row][c1.col].y; var c2x = board[c2.row][c2.col].x, c2y = board[c2.row][c2.col].y; tween(board[c1.row][c1.col], { x: c2x, y: c2y }, { duration: 220, easing: tween.cubicOut }); tween(board[c2.row][c2.col], { x: c1x, y: c1y }, { duration: 220, easing: tween.cubicOut }); // Swap positions in board array var tmp = board[c1.row][c1.col]; board[c1.row][c1.col] = board[c2.row][c2.col]; board[c2.row][c2.col] = tmp; // Update row/col board[c1.row][c1.col].row = c1.row; board[c1.row][c1.col].col = c1.col; board[c2.row][c2.col].row = c2.row; board[c2.row][c2.col].col = c2.col; clearPowerMode(); LK.setTimeout(function () { startCascadeLoop(); }, 400); } } // Freeze: prevent joker from acting as joker for next reshuffle/spin else if (powerMode === "freeze") { var crystal = board[r][c]; if (crystal && crystal.type === "joker" && !crystal.frozen && freezeUsedCount < freezeMaxCount) { crystal.frozen = true; freezeUsedCount++; // Visually indicate frozen state tween(crystal, { alpha: 0.5 }, { duration: 300, easing: tween.easeOut }); // Show freeze frame if (typeof crystal.setFreezeFrame === "function") { crystal.setFreezeFrame(true); } // If reached max, disable freeze button if (freezeUsedCount >= freezeMaxCount) { freezeBtnBg.alpha = 0.3; freezeBtnContainer.interactive = false; freezeBtnContainer.buttonMode = false; } clearPowerMode(); } } }; })(row, col); } } } // Call this after board is filled or refreshed applyPowerCrystalInteractivity(); // --- Patch: When filling board, re-apply crystal interactivity for powers --- function refreshCrystalInteractivity() { for (var row = 0; row < BOARD_ROWS; row++) { if (!board[row]) continue; for (var col = 0; col < BOARD_COLS; col++) { var crystal = board[row][col]; if (!crystal) continue; crystal.interactive = true; crystal.buttonMode = true; crystal.down = function () {}; // Restore freeze frame if frozen if (crystal.type === "joker" && crystal.frozen && typeof crystal.setFreezeFrame === "function") { crystal.setFreezeFrame(true); crystal.alpha = 0.5; } else if (typeof crystal.setFreezeFrame === "function") { crystal.setFreezeFrame(false); crystal.alpha = 1; } } } // Re-apply power crystal interactivity applyPowerCrystalInteractivity(); } // --- Touch to Spin/Reshuffle (tap anywhere else, fallback for desktop) --- // Removed global tap-to-reshuffle so only Spin button restarts the game // --- Game Over/Win (not used, slot is endless) --- // --- Game Update (not needed, all logic is event/cascade driven) --- game.update = function () { // No per-frame logic needed }; // --- Start the game --- startGame(); ;
===================================================================
--- original.js
+++ change.js
@@ -169,8 +169,16 @@
crystal.x = x;
crystal.y = y;
crystal.resetVisual();
game.addChild(crystal);
+ // Make crystal fixed: prevent any movement or change
+ crystal.interactive = false;
+ crystal.buttonMode = false;
+ crystal.down = function () {};
+ crystal.pop = function () {};
+ crystal.setType = function (type) {};
+ crystal.resetVisual = function () {};
+ crystal.setFreezeFrame = function () {};
return crystal;
}
function fillBoardRandom() {
for (var row = 0; row < BOARD_ROWS; row++) {