/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var DropShape = Container.expand(function (shapeType) { var self = Container.call(this); self.shapeType = shapeType; self.speed = 0; self.targetY = 0; self.isMoving = false; self.lane = 0; self.row = -1; var assetId = shapeType; var shapeGraphics = self.attachAsset(assetId, { anchorX: 0.5, anchorY: 0.5, scaleX: 1.25, scaleY: 1.25 }); self.startDrop = function (lane, startY, endY, targetRow) { self.lane = lane; self.y = startY; self.targetY = endY; self.targetRow = targetRow; self.speed = 120; // Double the speed for much faster movement self.isMoving = true; self.rotationComplete = false; // Add slot machine spinning effect - faster rotation tween(self, { rotation: Math.PI * 4 }, { duration: 800, // Much faster rotation animation easing: tween.easeOut, onFinish: function onFinish() { self.rotationComplete = true; } }); }; self.update = function () { if (self.isMoving) { self.y += self.speed; // Much faster settling with aggressive deceleration var distanceToTarget = Math.abs(self.targetY - self.y); if (distanceToTarget < 150) { self.speed = Math.max(8, self.speed * 0.85); // Higher minimum speed and faster deceleration } // Stop at target with bounce effect if (self.y >= self.targetY) { self.y = self.targetY; self.isMoving = false; self.speed = 0; // No bounce animation to keep consistent size // Calculate which row this shape is in - use targetRow if available if (self.targetRow !== undefined) { self.row = self.targetRow; } else { self.row = Math.floor((self.y - gridStartY) / (cellSize + cellMargin)); } } } }; return self; }); var GoodsItem = Container.expand(function (goodsType) { var self = Container.call(this); self.goodsType = goodsType; self.isFromScore = false; // Code-based marker for score items var itemGraphics = self.attachAsset(goodsType, { anchorX: 0.5, anchorY: 0.5, scaleX: 1.25, scaleY: 1.25 }); self.down = function (x, y, obj) { // Prevent interaction while any sequence or animation is running if (isScoreRefunding || isSequenceRunning || isTweenAnimating) return; // Check if this item is from score and currently in inventory slot if (self.isFromScore && currentInventoryItem === self) { // Item is in inventory slot, destroy and refund to score // Set refund flag to prevent multiple clicks isScoreRefunding = true; // Store reference to item being refunded var itemToRefund = self; // Calculate score text position in game coordinates var targetX = 1024; // Center of screen horizontally var targetY = 150; // Below score text instead of at score text position // Animate item moving towards score display with shrinking effect tween(itemToRefund, { x: targetX, y: targetY, scaleX: 0.3, scaleY: 0.3, alpha: 0.7 }, { duration: 150, // Double speed (half duration) easing: tween.easeOut, onFinish: function onFinish() { // Add score and update display after animation LK.setScore(LK.getScore() + 1000); updateScore(); // Flash score text tween(scoreTxt, { scaleX: 1.3, scaleY: 1.3 }, { duration: 100, onFinish: function onFinish() { tween(scoreTxt, { scaleX: 1.0, scaleY: 1.0 }, { duration: 100 }); } }); // Destroy item after score animation starts LK.setTimeout(function () { itemToRefund.destroy(); isScoreRefunding = false; }, 50); } }); // Clear from inventory currentInventoryItem = null; return; } // Check if this item is currently in goods grid (regardless of score status) var gridIndex = goodsGrid.indexOf(self); if (gridIndex !== -1) { // Item is in goods grid, move it to inventory slot moveToInventory(self); return; } // Move this item to inventory slot moveToInventory(self); }; return self; }); var Lever = Container.expand(function () { var self = Container.call(this); self.isPulled = false; self.canPull = true; var leverBase = self.attachAsset('lever', { anchorX: 0.5, anchorY: 1.0 }); self.leverHandle = self.attachAsset('leverHandle', { anchorX: 0.5, anchorY: 0.5 }); self.leverHandle.y = -700; self.pull = function () { if (!self.canPull || isShifting || isAnimating) return; // Check if player has enough money (10₺ required) if (money < 10) return; // Deduct 10₺ for using the slot machine money -= 10; updateMoney(); pullCount++; // Increment pull count self.canPull = false; self.isPulled = true; LK.getSound('leverPull').play(); // Animate lever handle moving down - much faster tween(self.leverHandle, { y: -100 }, { duration: 15, easing: tween.easeOut }); // Keep lever pulled state - will be reset on touch release // Allow immediate next pull self.canPull = true; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x2a1810 }); /**** * Game Code ****/ var lanes = []; var dropItems = []; var cellSize = 300; // Square cell size var cellMargin = 15; // 15 pixel margin between cells var totalGridWidth = 4 * cellSize + 3 * cellMargin; // Total width of 4 columns with margins var totalGridHeight = 4 * cellSize + 3 * cellMargin; // Total height of 4 rows with margins var gridStartX = (2048 - totalGridWidth) / 2 - 200; // Shift the 4x5 grid to the left var gridStartY = 600 - (cellSize + cellMargin); // Shift grid up by one grid cell height var laneWidth = cellSize + cellMargin; // Width per column including margin var laneBackgroundWidth = cellSize; // Square cell background var cellHeight = cellSize + cellMargin; // Height per row including margin var shapeTypes = ['karpuz', 'ananas', 'greenShape', 'muz', 'orange', 'apple']; var lever; var scoreTxt; var money = 0; var moneyTxt; var goodsGrid = []; var inventorySlot = null; var currentInventoryItem = null; var sellButton = null; var buyButton = null; var goodsTypes = ['corn', 'grape', 'bread', 'cheese', 'meat', 'fish']; // Create background - render first to be behind all other elements var background = LK.getAsset('background', { anchorX: 0, anchorY: 0 }); background.x = 0; background.y = 0; game.addChild(background); // Create lane backgrounds for 4x4 grid - render first to be behind other elements for (var col = 0; col < 4; col++) { for (var row = 0; row < 4; row++) { var cellBack = LK.getAsset('hucre', { width: cellSize, height: cellSize, anchorX: 0.5, anchorY: 0.5 }); cellBack.x = gridStartX + col * (cellSize + cellMargin) + cellSize / 2; cellBack.y = gridStartY + row * (cellSize + cellMargin) + cellSize / 2; game.addChild(cellBack); } } // Create goods grid backgrounds (4x3) - render first to be behind other elements var goodsGridStartX = gridStartX; var goodsGridStartY = gridStartY + totalGridHeight + 100; var goodsCellSize = cellSize; // Use same size as main grid cells (300px) var goodsMargin = cellMargin; // Use same margin as main grid (15px) for (var row = 0; row < 3; row++) { for (var col = 0; col < 4; col++) { // Create cell background var cellBack = LK.getAsset('goodsCell', { width: goodsCellSize, height: goodsCellSize, anchorX: 0.5, anchorY: 0.5 }); cellBack.x = goodsGridStartX + col * (goodsCellSize + goodsMargin) + goodsCellSize / 2; cellBack.y = goodsGridStartY + row * (goodsCellSize + goodsMargin) + goodsCellSize / 2; game.addChild(cellBack); } } // Create inventory slot background - render first to be behind other elements inventorySlot = LK.getAsset('inventorySlot', { width: goodsCellSize, height: goodsCellSize, anchorX: 0.5, anchorY: 0.5 }); inventorySlot.x = 1750; inventorySlot.y = goodsGridStartY + goodsCellSize / 2; inventorySlot.down = function (x, y, obj) { // Prevent interaction while any sequence or animation is running if (isScoreRefunding || isSequenceRunning || isTweenAnimating) return; // Prevent interaction when inventory slot is empty if (!currentInventoryItem) return; // If there's an item in inventory, handle refund if it's from score if (currentInventoryItem && currentInventoryItem.isFromScore) { // Set refund flag to prevent multiple clicks isScoreRefunding = true; // Store reference to item being refunded var itemToRefund = currentInventoryItem; // Calculate score text position in game coordinates var targetX = 1024; // Center of screen horizontally var targetY = 150; // Below score text instead of at score text position // Animate item moving towards score display with shrinking effect tween(itemToRefund, { x: targetX, y: targetY, scaleX: 0.3, scaleY: 0.3, alpha: 0.7 }, { duration: 150, // Double speed (half duration) easing: tween.easeOut, onFinish: function onFinish() { // Add score and update display after animation LK.setScore(LK.getScore() + 1000); updateScore(); // Flash score text tween(scoreTxt, { scaleX: 1.3, scaleY: 1.3 }, { duration: 100, onFinish: function onFinish() { tween(scoreTxt, { scaleX: 1.0, scaleY: 1.0 }, { duration: 100 }); } }); // Destroy item after score animation starts LK.setTimeout(function () { itemToRefund.destroy(); isScoreRefunding = false; }, 50); } }); // Clear from goods grid if it was placed there var gridIndex = goodsGrid.indexOf(currentInventoryItem); if (gridIndex !== -1) { goodsGrid[gridIndex] = null; } currentInventoryItem = null; return; } else if (currentInventoryItem && !currentInventoryItem.isFromScore) { // Only allow non-score items to move to goods grid var gridIndex = goodsGrid.indexOf(currentInventoryItem); if (gridIndex !== -1) { var row = Math.floor(gridIndex / 4); var col = gridIndex % 4; var targetX = goodsGridStartX + col * (goodsCellSize + goodsMargin) + goodsCellSize / 2; var targetY = goodsGridStartY + row * (goodsCellSize + goodsMargin) + goodsCellSize / 2; tween(currentInventoryItem, { x: targetX, y: targetY }, { duration: 300, easing: tween.easeOut }); } currentInventoryItem = null; } else if (LK.getScore() >= 1000) { // Only generate item if inventory is empty and score >= 1000 var randomGoodsType = goodsTypes[Math.floor(Math.random() * goodsTypes.length)]; var goodsItem = new GoodsItem(randomGoodsType); goodsItem.x = inventorySlot.x; goodsItem.y = inventorySlot.y; // Mark as item generated from score goodsItem.isFromScore = true; game.addChild(goodsItem); currentInventoryItem = goodsItem; // Deduct 1000 from score LK.setScore(LK.getScore() - 1000); updateScore(); } }; game.addChild(inventorySlot); // Create buy button below inventory slot buyButton = LK.getAsset('buyButton', { width: goodsCellSize, height: goodsCellSize / 2, anchorX: 0.5, anchorY: 0.5 }); buyButton.x = inventorySlot.x; buyButton.y = inventorySlot.y + goodsCellSize / 2 + goodsMargin + goodsCellSize / 4; game.addChild(buyButton); // Create sell button below buy button sellButton = LK.getAsset('sellButton', { width: goodsCellSize, height: goodsCellSize / 2, anchorX: 0.5, anchorY: 0.5 }); sellButton.x = inventorySlot.x; sellButton.y = buyButton.y + goodsCellSize / 2 + goodsMargin; game.addChild(sellButton); // Result cell removed // Create lever lever = game.addChild(new Lever()); lever.x = 1700; // Move to the left lever.y = 1400 - (cellSize + cellMargin); // Move up by one cell height // Create score display scoreTxt = new Text2('Skor: 0', { size: 80, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Create money display moneyTxt = new Text2('Para: 0₺', { size: 60, fill: 0x00ff00 }); moneyTxt.anchor.set(0.5, 0); moneyTxt.y = 100; LK.gui.top.addChild(moneyTxt); // Create goods items after backgrounds are rendered for (var row = 0; row < 3; row++) { for (var col = 0; col < 4; col++) { // Only create goods item for the first cell (start with 1 item) if (row === 0 && col === 0) { var randomGoodsType = goodsTypes[Math.floor(Math.random() * goodsTypes.length)]; var goodsItem = new GoodsItem(randomGoodsType); var cellX = goodsGridStartX + col * (goodsCellSize + goodsMargin) + goodsCellSize / 2; var cellY = goodsGridStartY + row * (goodsCellSize + goodsMargin) + goodsCellSize / 2; goodsItem.x = cellX; goodsItem.y = cellY; goodsItem.scaleX = 1.25; goodsItem.scaleY = 1.25; game.addChild(goodsItem); goodsGrid.push(goodsItem); } else { goodsGrid.push(null); } } } // Add buy button text var buyButtonText = new Text2('Al', { size: 80, fill: 0xffffff }); buyButtonText.anchor.set(0.5, 0.5); buyButtonText.x = buyButton.x; buyButtonText.y = buyButton.y; game.addChild(buyButtonText); // Add sell button text var sellButtonText = new Text2('Sat', { size: 80, fill: 0xffffff }); sellButtonText.anchor.set(0.5, 0.5); sellButtonText.x = sellButton.x; sellButtonText.y = sellButton.y; game.addChild(sellButtonText); function updateScore() { scoreTxt.setText('Skor: ' + LK.getScore()); } function updateMoney() { moneyTxt.setText('Para: ' + money + '₺'); } function moveToInventory(goodsItem) { // If clicking on the same item that's already in inventory, return it to grid if (currentInventoryItem === goodsItem) { var gridIndex = goodsGrid.indexOf(currentInventoryItem); if (gridIndex !== -1) { var row = Math.floor(gridIndex / 4); var col = gridIndex % 4; var targetX = goodsGridStartX + col * (goodsCellSize + goodsMargin) + goodsCellSize / 2; var targetY = goodsGridStartY + row * (goodsCellSize + goodsMargin) + goodsCellSize / 2; isTweenAnimating = true; tween(currentInventoryItem, { x: targetX, y: targetY }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { isTweenAnimating = false; } }); } currentInventoryItem = null; return; } if (currentInventoryItem) { // Return current item to its original position in grid var gridIndex = goodsGrid.indexOf(currentInventoryItem); if (gridIndex !== -1) { var row = Math.floor(gridIndex / 4); var col = gridIndex % 4; var targetX = goodsGridStartX + col * (goodsCellSize + goodsMargin) + goodsCellSize / 2; var targetY = goodsGridStartY + row * (goodsCellSize + goodsMargin) + goodsCellSize / 2; isTweenAnimating = true; tween(currentInventoryItem, { x: targetX, y: targetY }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { isTweenAnimating = false; } }); } } // Move new item to inventory - preserve score flag currentInventoryItem = goodsItem; // Keep the score flag so items can still be refunded if they were from score // currentInventoryItem.isFromScore remains unchanged isTweenAnimating = true; tween(goodsItem, { x: inventorySlot.x, y: inventorySlot.y }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { isTweenAnimating = false; } }); } function sellItem() { if (currentInventoryItem) { // Prevent interactions during sell animation isTweenAnimating = true; // Store reference to item being sold var itemToSell = currentInventoryItem; // Calculate money text position in game coordinates var moneyWorldPos = LK.gui.toLocal(moneyTxt.position); var targetX = 1024; // Center of screen horizontally var targetY = 250; // Below money text instead of at money text position // Animate item moving towards money display with shrinking effect tween(itemToSell, { x: targetX, y: targetY, scaleX: 0.3, scaleY: 0.3, alpha: 0.7 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { // Add money and update display after animation money += 100; updateMoney(); // Flash money text tween(moneyTxt, { scaleX: 1.3, scaleY: 1.3 }, { duration: 200, onFinish: function onFinish() { tween(moneyTxt, { scaleX: 1.0, scaleY: 1.0 }, { duration: 200 }); } }); // Destroy item after money animation starts LK.setTimeout(function () { itemToSell.destroy(); isTweenAnimating = false; }, 100); } }); // Remove sold item from grid and inventory var gridIndex = goodsGrid.indexOf(currentInventoryItem); if (gridIndex !== -1) { goodsGrid[gridIndex] = null; } currentInventoryItem = null; } } function buyItemWithScore() { // Check if player has enough score (1000 required) if (LK.getScore() < 1000) return; // Check if inventory slot is empty if (currentInventoryItem !== null) return; // Prevent interactions during buy animation isTweenAnimating = true; // Deduct 1000 from score LK.setScore(LK.getScore() - 1000); updateScore(); // Flash score text tween(scoreTxt, { scaleX: 1.3, scaleY: 1.3 }, { duration: 200, onFinish: function onFinish() { tween(scoreTxt, { scaleX: 1.0, scaleY: 1.0 }, { duration: 200 }); } }); // Create new random goods item starting from score position var randomGoodsType = goodsTypes[Math.floor(Math.random() * goodsTypes.length)]; var goodsItem = new GoodsItem(randomGoodsType); // Start item at score text position goodsItem.x = 1024; // Center of screen horizontally goodsItem.y = 150; // Below score text // Start small and transparent goodsItem.scaleX = 0.3; goodsItem.scaleY = 0.3; goodsItem.alpha = 0.7; // Mark as item generated from score goodsItem.isFromScore = true; game.addChild(goodsItem); // Animate item moving from score to inventory slot tween(goodsItem, { x: inventorySlot.x, y: inventorySlot.y, scaleX: 1.25, scaleY: 1.25, alpha: 1.0 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { isTweenAnimating = false; } }); currentInventoryItem = goodsItem; } function buyItem() { // Original buy functionality (unchanged) // Check if player has enough money (50₺ required) if (money < 50) return; // Find first empty slot in goods grid var emptySlotIndex = -1; for (var i = 0; i < goodsGrid.length; i++) { if (goodsGrid[i] === null) { emptySlotIndex = i; break; } } // If no empty slot, don't buy if (emptySlotIndex === -1) return; // Deduct money for buying item money -= 50; updateMoney(); // Flash money text tween(moneyTxt, { scaleX: 1.3, scaleY: 1.3 }, { duration: 200, onFinish: function onFinish() { tween(moneyTxt, { scaleX: 1.0, scaleY: 1.0 }, { duration: 200 }); } }); // Create new random goods item var randomGoodsType = goodsTypes[Math.floor(Math.random() * goodsTypes.length)]; var goodsItem = new GoodsItem(randomGoodsType); // Calculate position based on empty slot index var row = Math.floor(emptySlotIndex / 4); var col = emptySlotIndex % 4; var targetX = goodsGridStartX + col * (goodsCellSize + goodsMargin) + goodsCellSize / 2; var targetY = goodsGridStartY + row * (goodsCellSize + goodsMargin) + goodsCellSize / 2; goodsItem.x = targetX; goodsItem.y = targetY; goodsItem.scaleX = 1.25; goodsItem.scaleY = 1.25; game.addChild(goodsItem); goodsGrid[emptySlotIndex] = goodsItem; } function getRandomShape() { var shapeType = shapeTypes[Math.floor(Math.random() * shapeTypes.length)]; return { shapeType: shapeType }; } function spawnShapes() { spawnNewShapes(); } function spawnNewShapes() { // Prevent spawning if already animating if (isAnimating || isSequenceRunning) return; // Set animation flags to prevent all interactions isAnimating = true; isSequenceRunning = true; // Fill all rows sequentially starting from row 3 (bottom) going up to row 0 (top) fillRowSequentially(3); } function fillRowSequentially(currentRow) { if (currentRow < 0) { // All 4 horizontal rows filled, now check vertical columns checkColumnsForMatches(function () { // All rows and columns checked, clear all animation flags isAnimating = false; isSequenceRunning = false; }); return; } // Fill current row with shapes var currentRowShapes = []; for (var i = 0; i < 4; i++) { (function (laneIndex) { LK.setTimeout(function () { var shapeData = getRandomShape(); var shape = new DropShape(shapeData.shapeType); shape.x = gridStartX + laneIndex * (cellSize + cellMargin) + cellSize / 2; var targetY = gridStartY + currentRow * (cellSize + cellMargin) + cellSize / 2; shape.startDrop(laneIndex, gridStartY - 100, targetY, currentRow); currentRowShapes.push(shape); game.addChild(shape); dropItems.push(shape); }, laneIndex * 50); // Stagger each lane by 50ms })(i); } // Wait for all rotation animations to complete before proceeding function waitForRotationComplete() { var allRotationComplete = true; for (var i = 0; i < currentRowShapes.length; i++) { if (!currentRowShapes[i].rotationComplete) { allRotationComplete = false; break; } } if (allRotationComplete) { // All rotations complete, now check matches and fill next row checkMatchesForRow(currentRow, function () { // After checking matches for current row, fill the next row up fillRowSequentially(currentRow - 1); }); } else { // Check again in 50ms LK.setTimeout(waitForRotationComplete, 50); } } // Start checking after shapes are spawned (account for stagger time) LK.setTimeout(waitForRotationComplete, 300); } function checkMatches() { // Check result row (row 3 - bottom row) for matches checkMatchesForRow(3); } function checkMatchesForRow(targetRow, callback) { // Check specific row for matches var rowShapes = []; for (var i = 0; i < dropItems.length; i++) { if (dropItems[i].row === targetRow) { rowShapes.push(dropItems[i]); } } if (rowShapes.length < 2) { // After row checking is complete, call final callback without column checking if (callback) callback(); return; } // Count identical shapes (same shapeType) var shapeTypeCount = {}; for (var i = 0; i < rowShapes.length; i++) { var shape = rowShapes[i]; shapeTypeCount[shape.shapeType] = (shapeTypeCount[shape.shapeType] || 0) + 1; } // Find all matching groups var matchingGroups = []; for (var key in shapeTypeCount) { if (shapeTypeCount[key] === 4) { matchingGroups.push({ type: key, count: 4, points: 500 }); } else if (shapeTypeCount[key] === 3) { matchingGroups.push({ type: key, count: 3, points: 250 }); } else if (shapeTypeCount[key] === 2) { matchingGroups.push({ type: key, count: 2, points: 50 }); } } if (matchingGroups.length > 0) { // Process each matching group sequentially, then call final callback processMatchingGroups(matchingGroups, rowShapes, 0, callback); } else { // No horizontal match, call final callback if (callback) callback(); } } function processMatchingGroups(matchingGroups, rowShapes, groupIndex, callback) { if (groupIndex >= matchingGroups.length) { // All groups processed, call final callback if (callback) callback(); return; } var group = matchingGroups[groupIndex]; var points = group.points; // Add points for this group LK.setScore(LK.getScore() + points); updateScore(); updateMoney(); // Play sound based on match count if (points === 500 && group.count === 4) { LK.getSound('4xMatch').play(); } else if (points === 250) { LK.getSound('3xMatch').play(); } else if (points === 50 && group.count === 2) { LK.getSound('2xMatch').play(); } // Enhanced visual feedback for wins var flashColor = points >= 500 ? 0xffd700 : points >= 250 ? 0xff6600 : points >= 50 ? 0xffffff : 0xffffff; // Collect shapes for this specific group var scoringShapes = []; for (var i = 0; i < rowShapes.length; i++) { var shape = rowShapes[i]; if (shape.shapeType === group.type) { scoringShapes.push(shape); } } // Animate only the scoring shapes for this group var animationsCompleted = 0; var totalAnimations = scoringShapes.length; for (var i = 0; i < scoringShapes.length; i++) { var shape = scoringShapes[i]; LK.effects.flashObject(shape, flashColor, 1000); // Add temporary scaling and glow effect (function (currentShape) { tween(currentShape, { scaleX: 1.5, scaleY: 1.5, alpha: 1.5 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { // Return to original size and alpha tween(currentShape, { scaleX: 1.0, scaleY: 1.0, alpha: 1.0 }, { duration: 200, easing: tween.easeIn, onFinish: function onFinish() { animationsCompleted++; if (animationsCompleted >= totalAnimations) { // All animations for this group completed, process next group after delay LK.setTimeout(function () { processMatchingGroups(matchingGroups, rowShapes, groupIndex + 1, callback); }, 200); // Small delay between groups } } }); } }); })(shape); } // Animate score text on big wins if (points >= 250) { tween(scoreTxt, { scaleX: 1.2, scaleY: 1.2 }, { duration: 200, onFinish: function onFinish() { tween(scoreTxt, { scaleX: 1.0, scaleY: 1.0 }, { duration: 200 }); } }); } } function isGridFull() { for (var laneIndex = 0; laneIndex < 4; laneIndex++) { var occupiedRows = 0; for (var j = 0; j < dropItems.length; j++) { if (dropItems[j].lane === laneIndex && !dropItems[j].isMoving) { occupiedRows++; } } if (occupiedRows >= 4) { return true; } } return false; } function shiftShapesDown() { isShifting = true; isAnimating = true; // Move all shapes down by one row var shapesToShift = 0; var shapesCompleted = 0; // Count shapes that need to be shifted for (var i = 0; i < dropItems.length; i++) { if (!dropItems[i].isMoving) { shapesToShift++; } } for (var i = 0; i < dropItems.length; i++) { var shape = dropItems[i]; if (!shape.isMoving) { shape.row += 1; var newTargetY = gridStartY + shape.row * (cellSize + cellMargin) + cellSize / 2; // Animate the shift down - much faster tween(shape, { y: newTargetY }, { duration: 120, // Much faster shift animation easing: tween.easeOut, onFinish: function onFinish() { shapesCompleted++; if (shapesCompleted >= shapesToShift) { isShifting = false; isAnimating = false; } } }); } } // Fallback to reset flag if no shapes to shift if (shapesToShift === 0) { isShifting = false; isAnimating = false; } } function cleanupOffscreenShapes() { // Check if any shape has reached row 4 (beyond the 4x4 grid) var shouldClearAll = false; for (var i = 0; i < dropItems.length; i++) { if (dropItems[i].row >= 4) { shouldClearAll = true; break; } } // If any shape reached row 4, clear all shapes from the grid if (shouldClearAll) { for (var i = dropItems.length - 1; i >= 0; i--) { var shape = dropItems[i]; shape.destroy(); dropItems.splice(i, 1); } } else { // Original cleanup logic for shapes that might be off-screen for (var i = dropItems.length - 1; i >= 0; i--) { var shape = dropItems[i]; // Clean up shapes that go beyond the bottom of the 4x4 grid (row 4 and beyond) if (shape.row >= 4) { // No scaling animation to keep consistent size shape.destroy(); dropItems.splice(i, 1); } } } } var lastLeverPulled = false; var isDragging = false; var dragStartY = 0; var dragThreshold = 200; // Minimum drag distance to trigger slot var isShifting = false; // Flag to prevent lever pulling during animations var isAnimating = false; // Flag to track if any animations are ongoing var pullCount = 0; // Track number of pulls var isScoreRefunding = false; // Flag to prevent clicks during score refund var isSequenceRunning = false; // Flag to prevent interactions during any sequence/animation var isTweenAnimating = false; // Flag to track tween animations // Add touch/drag functionality to game - only near lever handle game.down = function (x, y, obj) { // Prevent interaction while any sequence or animation is running if (isSequenceRunning || isTweenAnimating) return; // Check if sell button was clicked var sellButtonDistance = Math.sqrt(Math.pow(x - sellButton.x, 2) + Math.pow(y - sellButton.y, 2)); if (sellButtonDistance <= goodsCellSize / 2) { sellItem(); return; } // Check if buy button was clicked var buyButtonDistance = Math.sqrt(Math.pow(x - buyButton.x, 2) + Math.pow(y - buyButton.y, 2)); if (buyButtonDistance <= goodsCellSize / 2) { buyItemWithScore(); return; } // Check if clicked on goods grid cells when inventory has item if (currentInventoryItem) { for (var row = 0; row < 3; row++) { //{70} for (var col = 0; col < 4; col++) { var cellX = goodsGridStartX + col * (goodsCellSize + goodsMargin) + goodsCellSize / 2; var cellY = goodsGridStartY + row * (goodsCellSize + goodsMargin) + goodsCellSize / 2; var cellDistance = Math.sqrt(Math.pow(x - cellX, 2) + Math.pow(y - cellY, 2)); if (cellDistance <= goodsCellSize / 2) { var gridIndex = row * 4 + col; // Move inventory item to any clicked cell (empty or occupied) // Check if this item was already in the grid (existing item being moved) var wasAlreadyInGrid = goodsGrid.indexOf(currentInventoryItem) !== -1; var itemToMove = currentInventoryItem; // If target cell is occupied, swap items if (goodsGrid[gridIndex] !== null) { var targetItem = goodsGrid[gridIndex]; // Move target item to inventory isTweenAnimating = true; tween(targetItem, { x: inventorySlot.x, y: inventorySlot.y }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { isTweenAnimating = false; } }); // Keep target item's score flag so it can still be refunded if it was from score // targetItem.isFromScore remains unchanged currentInventoryItem = targetItem; } else { currentInventoryItem = null; } // Move the item to the clicked cell if (itemToMove) { isTweenAnimating = true; tween(itemToMove, { x: cellX, y: cellY }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { isTweenAnimating = false; } }); // Remove item from its old position if it was already in grid if (wasAlreadyInGrid) { var oldIndex = goodsGrid.indexOf(itemToMove); if (oldIndex !== -1) { goodsGrid[oldIndex] = null; } } // Place the item in the new grid position goodsGrid[gridIndex] = itemToMove; // Keep the score flag when placing in grid so it can still be refunded // itemToMove.isFromScore remains unchanged } return; } } } } if (!isShifting && !isAnimating) { // Calculate lever handle's world position var handleWorldX = lever.x; var handleWorldY = lever.y + lever.leverHandle.y; // Check if touch is near the lever handle (within 200 pixels) var distance = Math.sqrt(Math.pow(x - handleWorldX, 2) + Math.pow(y - handleWorldY, 2)); if (distance <= 200) { isDragging = true; dragStartY = y; } } }; game.move = function (x, y, obj) { if (isDragging && !isShifting && !isAnimating) { var dragDistance = y - dragStartY; // If dragged down enough, trigger lever pull if (dragDistance > dragThreshold) { lever.pull(); isDragging = false; // Prevent multiple triggers during same drag } } }; game.up = function (x, y, obj) { isDragging = false; // Only allow lever handle to return up when touch is released if (lever.isPulled) { // Animate lever handle back up when released - much faster tween(lever.leverHandle, { y: -700 }, { duration: 30, easing: tween.easeOut, onFinish: function onFinish() { // Play lever release sound when handle reaches top LK.getSound('leverRelease').play(); // Clear all cells first for (var i = dropItems.length - 1; i >= 0; i--) { var shape = dropItems[i]; shape.destroy(); dropItems.splice(i, 1); } // Reset isFromScore flag for all items when slot is pulled if (currentInventoryItem) { currentInventoryItem.isFromScore = false; } for (var i = 0; i < goodsGrid.length; i++) { if (goodsGrid[i] !== null) { goodsGrid[i].isFromScore = false; } } // Start spawning immediately after clearing spawnShapes(); } }); lever.isPulled = false; } }; game.update = function () { cleanupOffscreenShapes(); // Keep lever handle always active - no passive state }; updateScore(); function checkColumnsForMatches(callback) { // Check all columns from left to right (column 0 to 3) checkColumnMatches(0, callback); } function checkColumnMatches(targetColumn, callback) { if (targetColumn >= 4) { // All columns checked, call final callback if (callback) callback(); return; } // Get all shapes in the target column var columnShapes = []; for (var i = 0; i < dropItems.length; i++) { if (dropItems[i].lane === targetColumn) { columnShapes.push(dropItems[i]); } } if (columnShapes.length < 2) { // Move to next column checkColumnMatches(targetColumn + 1, callback); return; } // Count identical shapes (same shapeType) in this column var shapeTypeCount = {}; for (var i = 0; i < columnShapes.length; i++) { var shape = columnShapes[i]; shapeTypeCount[shape.shapeType] = (shapeTypeCount[shape.shapeType] || 0) + 1; } // Find all matching groups in this column var matchingGroups = []; for (var key in shapeTypeCount) { if (shapeTypeCount[key] === 4) { matchingGroups.push({ type: key, count: 4, points: 500 }); } else if (shapeTypeCount[key] === 3) { matchingGroups.push({ type: key, count: 3, points: 250 }); } else if (shapeTypeCount[key] === 2) { matchingGroups.push({ type: key, count: 2, points: 50 }); } } if (matchingGroups.length > 0) { // Process each matching group sequentially for this column processMatchingGroups(matchingGroups, columnShapes, 0, function () { // After processing this column, move to next column checkColumnMatches(targetColumn + 1, callback); }); } else { // No match in this column, move to next column checkColumnMatches(targetColumn + 1, callback); } }
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var DropShape = Container.expand(function (shapeType) {
var self = Container.call(this);
self.shapeType = shapeType;
self.speed = 0;
self.targetY = 0;
self.isMoving = false;
self.lane = 0;
self.row = -1;
var assetId = shapeType;
var shapeGraphics = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.25,
scaleY: 1.25
});
self.startDrop = function (lane, startY, endY, targetRow) {
self.lane = lane;
self.y = startY;
self.targetY = endY;
self.targetRow = targetRow;
self.speed = 120; // Double the speed for much faster movement
self.isMoving = true;
self.rotationComplete = false;
// Add slot machine spinning effect - faster rotation
tween(self, {
rotation: Math.PI * 4
}, {
duration: 800,
// Much faster rotation animation
easing: tween.easeOut,
onFinish: function onFinish() {
self.rotationComplete = true;
}
});
};
self.update = function () {
if (self.isMoving) {
self.y += self.speed;
// Much faster settling with aggressive deceleration
var distanceToTarget = Math.abs(self.targetY - self.y);
if (distanceToTarget < 150) {
self.speed = Math.max(8, self.speed * 0.85); // Higher minimum speed and faster deceleration
}
// Stop at target with bounce effect
if (self.y >= self.targetY) {
self.y = self.targetY;
self.isMoving = false;
self.speed = 0;
// No bounce animation to keep consistent size
// Calculate which row this shape is in - use targetRow if available
if (self.targetRow !== undefined) {
self.row = self.targetRow;
} else {
self.row = Math.floor((self.y - gridStartY) / (cellSize + cellMargin));
}
}
}
};
return self;
});
var GoodsItem = Container.expand(function (goodsType) {
var self = Container.call(this);
self.goodsType = goodsType;
self.isFromScore = false; // Code-based marker for score items
var itemGraphics = self.attachAsset(goodsType, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.25,
scaleY: 1.25
});
self.down = function (x, y, obj) {
// Prevent interaction while any sequence or animation is running
if (isScoreRefunding || isSequenceRunning || isTweenAnimating) return;
// Check if this item is from score and currently in inventory slot
if (self.isFromScore && currentInventoryItem === self) {
// Item is in inventory slot, destroy and refund to score
// Set refund flag to prevent multiple clicks
isScoreRefunding = true;
// Store reference to item being refunded
var itemToRefund = self;
// Calculate score text position in game coordinates
var targetX = 1024; // Center of screen horizontally
var targetY = 150; // Below score text instead of at score text position
// Animate item moving towards score display with shrinking effect
tween(itemToRefund, {
x: targetX,
y: targetY,
scaleX: 0.3,
scaleY: 0.3,
alpha: 0.7
}, {
duration: 150,
// Double speed (half duration)
easing: tween.easeOut,
onFinish: function onFinish() {
// Add score and update display after animation
LK.setScore(LK.getScore() + 1000);
updateScore();
// Flash score text
tween(scoreTxt, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 100,
onFinish: function onFinish() {
tween(scoreTxt, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 100
});
}
});
// Destroy item after score animation starts
LK.setTimeout(function () {
itemToRefund.destroy();
isScoreRefunding = false;
}, 50);
}
});
// Clear from inventory
currentInventoryItem = null;
return;
}
// Check if this item is currently in goods grid (regardless of score status)
var gridIndex = goodsGrid.indexOf(self);
if (gridIndex !== -1) {
// Item is in goods grid, move it to inventory slot
moveToInventory(self);
return;
}
// Move this item to inventory slot
moveToInventory(self);
};
return self;
});
var Lever = Container.expand(function () {
var self = Container.call(this);
self.isPulled = false;
self.canPull = true;
var leverBase = self.attachAsset('lever', {
anchorX: 0.5,
anchorY: 1.0
});
self.leverHandle = self.attachAsset('leverHandle', {
anchorX: 0.5,
anchorY: 0.5
});
self.leverHandle.y = -700;
self.pull = function () {
if (!self.canPull || isShifting || isAnimating) return;
// Check if player has enough money (10₺ required)
if (money < 10) return;
// Deduct 10₺ for using the slot machine
money -= 10;
updateMoney();
pullCount++; // Increment pull count
self.canPull = false;
self.isPulled = true;
LK.getSound('leverPull').play();
// Animate lever handle moving down - much faster
tween(self.leverHandle, {
y: -100
}, {
duration: 15,
easing: tween.easeOut
});
// Keep lever pulled state - will be reset on touch release
// Allow immediate next pull
self.canPull = true;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2a1810
});
/****
* Game Code
****/
var lanes = [];
var dropItems = [];
var cellSize = 300; // Square cell size
var cellMargin = 15; // 15 pixel margin between cells
var totalGridWidth = 4 * cellSize + 3 * cellMargin; // Total width of 4 columns with margins
var totalGridHeight = 4 * cellSize + 3 * cellMargin; // Total height of 4 rows with margins
var gridStartX = (2048 - totalGridWidth) / 2 - 200; // Shift the 4x5 grid to the left
var gridStartY = 600 - (cellSize + cellMargin); // Shift grid up by one grid cell height
var laneWidth = cellSize + cellMargin; // Width per column including margin
var laneBackgroundWidth = cellSize; // Square cell background
var cellHeight = cellSize + cellMargin; // Height per row including margin
var shapeTypes = ['karpuz', 'ananas', 'greenShape', 'muz', 'orange', 'apple'];
var lever;
var scoreTxt;
var money = 0;
var moneyTxt;
var goodsGrid = [];
var inventorySlot = null;
var currentInventoryItem = null;
var sellButton = null;
var buyButton = null;
var goodsTypes = ['corn', 'grape', 'bread', 'cheese', 'meat', 'fish'];
// Create background - render first to be behind all other elements
var background = LK.getAsset('background', {
anchorX: 0,
anchorY: 0
});
background.x = 0;
background.y = 0;
game.addChild(background);
// Create lane backgrounds for 4x4 grid - render first to be behind other elements
for (var col = 0; col < 4; col++) {
for (var row = 0; row < 4; row++) {
var cellBack = LK.getAsset('hucre', {
width: cellSize,
height: cellSize,
anchorX: 0.5,
anchorY: 0.5
});
cellBack.x = gridStartX + col * (cellSize + cellMargin) + cellSize / 2;
cellBack.y = gridStartY + row * (cellSize + cellMargin) + cellSize / 2;
game.addChild(cellBack);
}
}
// Create goods grid backgrounds (4x3) - render first to be behind other elements
var goodsGridStartX = gridStartX;
var goodsGridStartY = gridStartY + totalGridHeight + 100;
var goodsCellSize = cellSize; // Use same size as main grid cells (300px)
var goodsMargin = cellMargin; // Use same margin as main grid (15px)
for (var row = 0; row < 3; row++) {
for (var col = 0; col < 4; col++) {
// Create cell background
var cellBack = LK.getAsset('goodsCell', {
width: goodsCellSize,
height: goodsCellSize,
anchorX: 0.5,
anchorY: 0.5
});
cellBack.x = goodsGridStartX + col * (goodsCellSize + goodsMargin) + goodsCellSize / 2;
cellBack.y = goodsGridStartY + row * (goodsCellSize + goodsMargin) + goodsCellSize / 2;
game.addChild(cellBack);
}
}
// Create inventory slot background - render first to be behind other elements
inventorySlot = LK.getAsset('inventorySlot', {
width: goodsCellSize,
height: goodsCellSize,
anchorX: 0.5,
anchorY: 0.5
});
inventorySlot.x = 1750;
inventorySlot.y = goodsGridStartY + goodsCellSize / 2;
inventorySlot.down = function (x, y, obj) {
// Prevent interaction while any sequence or animation is running
if (isScoreRefunding || isSequenceRunning || isTweenAnimating) return;
// Prevent interaction when inventory slot is empty
if (!currentInventoryItem) return;
// If there's an item in inventory, handle refund if it's from score
if (currentInventoryItem && currentInventoryItem.isFromScore) {
// Set refund flag to prevent multiple clicks
isScoreRefunding = true;
// Store reference to item being refunded
var itemToRefund = currentInventoryItem;
// Calculate score text position in game coordinates
var targetX = 1024; // Center of screen horizontally
var targetY = 150; // Below score text instead of at score text position
// Animate item moving towards score display with shrinking effect
tween(itemToRefund, {
x: targetX,
y: targetY,
scaleX: 0.3,
scaleY: 0.3,
alpha: 0.7
}, {
duration: 150,
// Double speed (half duration)
easing: tween.easeOut,
onFinish: function onFinish() {
// Add score and update display after animation
LK.setScore(LK.getScore() + 1000);
updateScore();
// Flash score text
tween(scoreTxt, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 100,
onFinish: function onFinish() {
tween(scoreTxt, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 100
});
}
});
// Destroy item after score animation starts
LK.setTimeout(function () {
itemToRefund.destroy();
isScoreRefunding = false;
}, 50);
}
});
// Clear from goods grid if it was placed there
var gridIndex = goodsGrid.indexOf(currentInventoryItem);
if (gridIndex !== -1) {
goodsGrid[gridIndex] = null;
}
currentInventoryItem = null;
return;
} else if (currentInventoryItem && !currentInventoryItem.isFromScore) {
// Only allow non-score items to move to goods grid
var gridIndex = goodsGrid.indexOf(currentInventoryItem);
if (gridIndex !== -1) {
var row = Math.floor(gridIndex / 4);
var col = gridIndex % 4;
var targetX = goodsGridStartX + col * (goodsCellSize + goodsMargin) + goodsCellSize / 2;
var targetY = goodsGridStartY + row * (goodsCellSize + goodsMargin) + goodsCellSize / 2;
tween(currentInventoryItem, {
x: targetX,
y: targetY
}, {
duration: 300,
easing: tween.easeOut
});
}
currentInventoryItem = null;
} else if (LK.getScore() >= 1000) {
// Only generate item if inventory is empty and score >= 1000
var randomGoodsType = goodsTypes[Math.floor(Math.random() * goodsTypes.length)];
var goodsItem = new GoodsItem(randomGoodsType);
goodsItem.x = inventorySlot.x;
goodsItem.y = inventorySlot.y;
// Mark as item generated from score
goodsItem.isFromScore = true;
game.addChild(goodsItem);
currentInventoryItem = goodsItem;
// Deduct 1000 from score
LK.setScore(LK.getScore() - 1000);
updateScore();
}
};
game.addChild(inventorySlot);
// Create buy button below inventory slot
buyButton = LK.getAsset('buyButton', {
width: goodsCellSize,
height: goodsCellSize / 2,
anchorX: 0.5,
anchorY: 0.5
});
buyButton.x = inventorySlot.x;
buyButton.y = inventorySlot.y + goodsCellSize / 2 + goodsMargin + goodsCellSize / 4;
game.addChild(buyButton);
// Create sell button below buy button
sellButton = LK.getAsset('sellButton', {
width: goodsCellSize,
height: goodsCellSize / 2,
anchorX: 0.5,
anchorY: 0.5
});
sellButton.x = inventorySlot.x;
sellButton.y = buyButton.y + goodsCellSize / 2 + goodsMargin;
game.addChild(sellButton);
// Result cell removed
// Create lever
lever = game.addChild(new Lever());
lever.x = 1700; // Move to the left
lever.y = 1400 - (cellSize + cellMargin); // Move up by one cell height
// Create score display
scoreTxt = new Text2('Skor: 0', {
size: 80,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Create money display
moneyTxt = new Text2('Para: 0₺', {
size: 60,
fill: 0x00ff00
});
moneyTxt.anchor.set(0.5, 0);
moneyTxt.y = 100;
LK.gui.top.addChild(moneyTxt);
// Create goods items after backgrounds are rendered
for (var row = 0; row < 3; row++) {
for (var col = 0; col < 4; col++) {
// Only create goods item for the first cell (start with 1 item)
if (row === 0 && col === 0) {
var randomGoodsType = goodsTypes[Math.floor(Math.random() * goodsTypes.length)];
var goodsItem = new GoodsItem(randomGoodsType);
var cellX = goodsGridStartX + col * (goodsCellSize + goodsMargin) + goodsCellSize / 2;
var cellY = goodsGridStartY + row * (goodsCellSize + goodsMargin) + goodsCellSize / 2;
goodsItem.x = cellX;
goodsItem.y = cellY;
goodsItem.scaleX = 1.25;
goodsItem.scaleY = 1.25;
game.addChild(goodsItem);
goodsGrid.push(goodsItem);
} else {
goodsGrid.push(null);
}
}
}
// Add buy button text
var buyButtonText = new Text2('Al', {
size: 80,
fill: 0xffffff
});
buyButtonText.anchor.set(0.5, 0.5);
buyButtonText.x = buyButton.x;
buyButtonText.y = buyButton.y;
game.addChild(buyButtonText);
// Add sell button text
var sellButtonText = new Text2('Sat', {
size: 80,
fill: 0xffffff
});
sellButtonText.anchor.set(0.5, 0.5);
sellButtonText.x = sellButton.x;
sellButtonText.y = sellButton.y;
game.addChild(sellButtonText);
function updateScore() {
scoreTxt.setText('Skor: ' + LK.getScore());
}
function updateMoney() {
moneyTxt.setText('Para: ' + money + '₺');
}
function moveToInventory(goodsItem) {
// If clicking on the same item that's already in inventory, return it to grid
if (currentInventoryItem === goodsItem) {
var gridIndex = goodsGrid.indexOf(currentInventoryItem);
if (gridIndex !== -1) {
var row = Math.floor(gridIndex / 4);
var col = gridIndex % 4;
var targetX = goodsGridStartX + col * (goodsCellSize + goodsMargin) + goodsCellSize / 2;
var targetY = goodsGridStartY + row * (goodsCellSize + goodsMargin) + goodsCellSize / 2;
isTweenAnimating = true;
tween(currentInventoryItem, {
x: targetX,
y: targetY
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
isTweenAnimating = false;
}
});
}
currentInventoryItem = null;
return;
}
if (currentInventoryItem) {
// Return current item to its original position in grid
var gridIndex = goodsGrid.indexOf(currentInventoryItem);
if (gridIndex !== -1) {
var row = Math.floor(gridIndex / 4);
var col = gridIndex % 4;
var targetX = goodsGridStartX + col * (goodsCellSize + goodsMargin) + goodsCellSize / 2;
var targetY = goodsGridStartY + row * (goodsCellSize + goodsMargin) + goodsCellSize / 2;
isTweenAnimating = true;
tween(currentInventoryItem, {
x: targetX,
y: targetY
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
isTweenAnimating = false;
}
});
}
}
// Move new item to inventory - preserve score flag
currentInventoryItem = goodsItem;
// Keep the score flag so items can still be refunded if they were from score
// currentInventoryItem.isFromScore remains unchanged
isTweenAnimating = true;
tween(goodsItem, {
x: inventorySlot.x,
y: inventorySlot.y
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
isTweenAnimating = false;
}
});
}
function sellItem() {
if (currentInventoryItem) {
// Prevent interactions during sell animation
isTweenAnimating = true;
// Store reference to item being sold
var itemToSell = currentInventoryItem;
// Calculate money text position in game coordinates
var moneyWorldPos = LK.gui.toLocal(moneyTxt.position);
var targetX = 1024; // Center of screen horizontally
var targetY = 250; // Below money text instead of at money text position
// Animate item moving towards money display with shrinking effect
tween(itemToSell, {
x: targetX,
y: targetY,
scaleX: 0.3,
scaleY: 0.3,
alpha: 0.7
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
// Add money and update display after animation
money += 100;
updateMoney();
// Flash money text
tween(moneyTxt, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 200,
onFinish: function onFinish() {
tween(moneyTxt, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 200
});
}
});
// Destroy item after money animation starts
LK.setTimeout(function () {
itemToSell.destroy();
isTweenAnimating = false;
}, 100);
}
});
// Remove sold item from grid and inventory
var gridIndex = goodsGrid.indexOf(currentInventoryItem);
if (gridIndex !== -1) {
goodsGrid[gridIndex] = null;
}
currentInventoryItem = null;
}
}
function buyItemWithScore() {
// Check if player has enough score (1000 required)
if (LK.getScore() < 1000) return;
// Check if inventory slot is empty
if (currentInventoryItem !== null) return;
// Prevent interactions during buy animation
isTweenAnimating = true;
// Deduct 1000 from score
LK.setScore(LK.getScore() - 1000);
updateScore();
// Flash score text
tween(scoreTxt, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 200,
onFinish: function onFinish() {
tween(scoreTxt, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 200
});
}
});
// Create new random goods item starting from score position
var randomGoodsType = goodsTypes[Math.floor(Math.random() * goodsTypes.length)];
var goodsItem = new GoodsItem(randomGoodsType);
// Start item at score text position
goodsItem.x = 1024; // Center of screen horizontally
goodsItem.y = 150; // Below score text
// Start small and transparent
goodsItem.scaleX = 0.3;
goodsItem.scaleY = 0.3;
goodsItem.alpha = 0.7;
// Mark as item generated from score
goodsItem.isFromScore = true;
game.addChild(goodsItem);
// Animate item moving from score to inventory slot
tween(goodsItem, {
x: inventorySlot.x,
y: inventorySlot.y,
scaleX: 1.25,
scaleY: 1.25,
alpha: 1.0
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
isTweenAnimating = false;
}
});
currentInventoryItem = goodsItem;
}
function buyItem() {
// Original buy functionality (unchanged)
// Check if player has enough money (50₺ required)
if (money < 50) return;
// Find first empty slot in goods grid
var emptySlotIndex = -1;
for (var i = 0; i < goodsGrid.length; i++) {
if (goodsGrid[i] === null) {
emptySlotIndex = i;
break;
}
}
// If no empty slot, don't buy
if (emptySlotIndex === -1) return;
// Deduct money for buying item
money -= 50;
updateMoney();
// Flash money text
tween(moneyTxt, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 200,
onFinish: function onFinish() {
tween(moneyTxt, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 200
});
}
});
// Create new random goods item
var randomGoodsType = goodsTypes[Math.floor(Math.random() * goodsTypes.length)];
var goodsItem = new GoodsItem(randomGoodsType);
// Calculate position based on empty slot index
var row = Math.floor(emptySlotIndex / 4);
var col = emptySlotIndex % 4;
var targetX = goodsGridStartX + col * (goodsCellSize + goodsMargin) + goodsCellSize / 2;
var targetY = goodsGridStartY + row * (goodsCellSize + goodsMargin) + goodsCellSize / 2;
goodsItem.x = targetX;
goodsItem.y = targetY;
goodsItem.scaleX = 1.25;
goodsItem.scaleY = 1.25;
game.addChild(goodsItem);
goodsGrid[emptySlotIndex] = goodsItem;
}
function getRandomShape() {
var shapeType = shapeTypes[Math.floor(Math.random() * shapeTypes.length)];
return {
shapeType: shapeType
};
}
function spawnShapes() {
spawnNewShapes();
}
function spawnNewShapes() {
// Prevent spawning if already animating
if (isAnimating || isSequenceRunning) return;
// Set animation flags to prevent all interactions
isAnimating = true;
isSequenceRunning = true;
// Fill all rows sequentially starting from row 3 (bottom) going up to row 0 (top)
fillRowSequentially(3);
}
function fillRowSequentially(currentRow) {
if (currentRow < 0) {
// All 4 horizontal rows filled, now check vertical columns
checkColumnsForMatches(function () {
// All rows and columns checked, clear all animation flags
isAnimating = false;
isSequenceRunning = false;
});
return;
}
// Fill current row with shapes
var currentRowShapes = [];
for (var i = 0; i < 4; i++) {
(function (laneIndex) {
LK.setTimeout(function () {
var shapeData = getRandomShape();
var shape = new DropShape(shapeData.shapeType);
shape.x = gridStartX + laneIndex * (cellSize + cellMargin) + cellSize / 2;
var targetY = gridStartY + currentRow * (cellSize + cellMargin) + cellSize / 2;
shape.startDrop(laneIndex, gridStartY - 100, targetY, currentRow);
currentRowShapes.push(shape);
game.addChild(shape);
dropItems.push(shape);
}, laneIndex * 50); // Stagger each lane by 50ms
})(i);
}
// Wait for all rotation animations to complete before proceeding
function waitForRotationComplete() {
var allRotationComplete = true;
for (var i = 0; i < currentRowShapes.length; i++) {
if (!currentRowShapes[i].rotationComplete) {
allRotationComplete = false;
break;
}
}
if (allRotationComplete) {
// All rotations complete, now check matches and fill next row
checkMatchesForRow(currentRow, function () {
// After checking matches for current row, fill the next row up
fillRowSequentially(currentRow - 1);
});
} else {
// Check again in 50ms
LK.setTimeout(waitForRotationComplete, 50);
}
}
// Start checking after shapes are spawned (account for stagger time)
LK.setTimeout(waitForRotationComplete, 300);
}
function checkMatches() {
// Check result row (row 3 - bottom row) for matches
checkMatchesForRow(3);
}
function checkMatchesForRow(targetRow, callback) {
// Check specific row for matches
var rowShapes = [];
for (var i = 0; i < dropItems.length; i++) {
if (dropItems[i].row === targetRow) {
rowShapes.push(dropItems[i]);
}
}
if (rowShapes.length < 2) {
// After row checking is complete, call final callback without column checking
if (callback) callback();
return;
}
// Count identical shapes (same shapeType)
var shapeTypeCount = {};
for (var i = 0; i < rowShapes.length; i++) {
var shape = rowShapes[i];
shapeTypeCount[shape.shapeType] = (shapeTypeCount[shape.shapeType] || 0) + 1;
}
// Find all matching groups
var matchingGroups = [];
for (var key in shapeTypeCount) {
if (shapeTypeCount[key] === 4) {
matchingGroups.push({
type: key,
count: 4,
points: 500
});
} else if (shapeTypeCount[key] === 3) {
matchingGroups.push({
type: key,
count: 3,
points: 250
});
} else if (shapeTypeCount[key] === 2) {
matchingGroups.push({
type: key,
count: 2,
points: 50
});
}
}
if (matchingGroups.length > 0) {
// Process each matching group sequentially, then call final callback
processMatchingGroups(matchingGroups, rowShapes, 0, callback);
} else {
// No horizontal match, call final callback
if (callback) callback();
}
}
function processMatchingGroups(matchingGroups, rowShapes, groupIndex, callback) {
if (groupIndex >= matchingGroups.length) {
// All groups processed, call final callback
if (callback) callback();
return;
}
var group = matchingGroups[groupIndex];
var points = group.points;
// Add points for this group
LK.setScore(LK.getScore() + points);
updateScore();
updateMoney();
// Play sound based on match count
if (points === 500 && group.count === 4) {
LK.getSound('4xMatch').play();
} else if (points === 250) {
LK.getSound('3xMatch').play();
} else if (points === 50 && group.count === 2) {
LK.getSound('2xMatch').play();
}
// Enhanced visual feedback for wins
var flashColor = points >= 500 ? 0xffd700 : points >= 250 ? 0xff6600 : points >= 50 ? 0xffffff : 0xffffff;
// Collect shapes for this specific group
var scoringShapes = [];
for (var i = 0; i < rowShapes.length; i++) {
var shape = rowShapes[i];
if (shape.shapeType === group.type) {
scoringShapes.push(shape);
}
}
// Animate only the scoring shapes for this group
var animationsCompleted = 0;
var totalAnimations = scoringShapes.length;
for (var i = 0; i < scoringShapes.length; i++) {
var shape = scoringShapes[i];
LK.effects.flashObject(shape, flashColor, 1000);
// Add temporary scaling and glow effect
(function (currentShape) {
tween(currentShape, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 1.5
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
// Return to original size and alpha
tween(currentShape, {
scaleX: 1.0,
scaleY: 1.0,
alpha: 1.0
}, {
duration: 200,
easing: tween.easeIn,
onFinish: function onFinish() {
animationsCompleted++;
if (animationsCompleted >= totalAnimations) {
// All animations for this group completed, process next group after delay
LK.setTimeout(function () {
processMatchingGroups(matchingGroups, rowShapes, groupIndex + 1, callback);
}, 200); // Small delay between groups
}
}
});
}
});
})(shape);
}
// Animate score text on big wins
if (points >= 250) {
tween(scoreTxt, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 200,
onFinish: function onFinish() {
tween(scoreTxt, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 200
});
}
});
}
}
function isGridFull() {
for (var laneIndex = 0; laneIndex < 4; laneIndex++) {
var occupiedRows = 0;
for (var j = 0; j < dropItems.length; j++) {
if (dropItems[j].lane === laneIndex && !dropItems[j].isMoving) {
occupiedRows++;
}
}
if (occupiedRows >= 4) {
return true;
}
}
return false;
}
function shiftShapesDown() {
isShifting = true;
isAnimating = true;
// Move all shapes down by one row
var shapesToShift = 0;
var shapesCompleted = 0;
// Count shapes that need to be shifted
for (var i = 0; i < dropItems.length; i++) {
if (!dropItems[i].isMoving) {
shapesToShift++;
}
}
for (var i = 0; i < dropItems.length; i++) {
var shape = dropItems[i];
if (!shape.isMoving) {
shape.row += 1;
var newTargetY = gridStartY + shape.row * (cellSize + cellMargin) + cellSize / 2;
// Animate the shift down - much faster
tween(shape, {
y: newTargetY
}, {
duration: 120,
// Much faster shift animation
easing: tween.easeOut,
onFinish: function onFinish() {
shapesCompleted++;
if (shapesCompleted >= shapesToShift) {
isShifting = false;
isAnimating = false;
}
}
});
}
}
// Fallback to reset flag if no shapes to shift
if (shapesToShift === 0) {
isShifting = false;
isAnimating = false;
}
}
function cleanupOffscreenShapes() {
// Check if any shape has reached row 4 (beyond the 4x4 grid)
var shouldClearAll = false;
for (var i = 0; i < dropItems.length; i++) {
if (dropItems[i].row >= 4) {
shouldClearAll = true;
break;
}
}
// If any shape reached row 4, clear all shapes from the grid
if (shouldClearAll) {
for (var i = dropItems.length - 1; i >= 0; i--) {
var shape = dropItems[i];
shape.destroy();
dropItems.splice(i, 1);
}
} else {
// Original cleanup logic for shapes that might be off-screen
for (var i = dropItems.length - 1; i >= 0; i--) {
var shape = dropItems[i];
// Clean up shapes that go beyond the bottom of the 4x4 grid (row 4 and beyond)
if (shape.row >= 4) {
// No scaling animation to keep consistent size
shape.destroy();
dropItems.splice(i, 1);
}
}
}
}
var lastLeverPulled = false;
var isDragging = false;
var dragStartY = 0;
var dragThreshold = 200; // Minimum drag distance to trigger slot
var isShifting = false; // Flag to prevent lever pulling during animations
var isAnimating = false; // Flag to track if any animations are ongoing
var pullCount = 0; // Track number of pulls
var isScoreRefunding = false; // Flag to prevent clicks during score refund
var isSequenceRunning = false; // Flag to prevent interactions during any sequence/animation
var isTweenAnimating = false; // Flag to track tween animations
// Add touch/drag functionality to game - only near lever handle
game.down = function (x, y, obj) {
// Prevent interaction while any sequence or animation is running
if (isSequenceRunning || isTweenAnimating) return;
// Check if sell button was clicked
var sellButtonDistance = Math.sqrt(Math.pow(x - sellButton.x, 2) + Math.pow(y - sellButton.y, 2));
if (sellButtonDistance <= goodsCellSize / 2) {
sellItem();
return;
}
// Check if buy button was clicked
var buyButtonDistance = Math.sqrt(Math.pow(x - buyButton.x, 2) + Math.pow(y - buyButton.y, 2));
if (buyButtonDistance <= goodsCellSize / 2) {
buyItemWithScore();
return;
}
// Check if clicked on goods grid cells when inventory has item
if (currentInventoryItem) {
for (var row = 0; row < 3; row++) {
//{70}
for (var col = 0; col < 4; col++) {
var cellX = goodsGridStartX + col * (goodsCellSize + goodsMargin) + goodsCellSize / 2;
var cellY = goodsGridStartY + row * (goodsCellSize + goodsMargin) + goodsCellSize / 2;
var cellDistance = Math.sqrt(Math.pow(x - cellX, 2) + Math.pow(y - cellY, 2));
if (cellDistance <= goodsCellSize / 2) {
var gridIndex = row * 4 + col;
// Move inventory item to any clicked cell (empty or occupied)
// Check if this item was already in the grid (existing item being moved)
var wasAlreadyInGrid = goodsGrid.indexOf(currentInventoryItem) !== -1;
var itemToMove = currentInventoryItem;
// If target cell is occupied, swap items
if (goodsGrid[gridIndex] !== null) {
var targetItem = goodsGrid[gridIndex];
// Move target item to inventory
isTweenAnimating = true;
tween(targetItem, {
x: inventorySlot.x,
y: inventorySlot.y
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
isTweenAnimating = false;
}
});
// Keep target item's score flag so it can still be refunded if it was from score
// targetItem.isFromScore remains unchanged
currentInventoryItem = targetItem;
} else {
currentInventoryItem = null;
}
// Move the item to the clicked cell
if (itemToMove) {
isTweenAnimating = true;
tween(itemToMove, {
x: cellX,
y: cellY
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
isTweenAnimating = false;
}
});
// Remove item from its old position if it was already in grid
if (wasAlreadyInGrid) {
var oldIndex = goodsGrid.indexOf(itemToMove);
if (oldIndex !== -1) {
goodsGrid[oldIndex] = null;
}
}
// Place the item in the new grid position
goodsGrid[gridIndex] = itemToMove;
// Keep the score flag when placing in grid so it can still be refunded
// itemToMove.isFromScore remains unchanged
}
return;
}
}
}
}
if (!isShifting && !isAnimating) {
// Calculate lever handle's world position
var handleWorldX = lever.x;
var handleWorldY = lever.y + lever.leverHandle.y;
// Check if touch is near the lever handle (within 200 pixels)
var distance = Math.sqrt(Math.pow(x - handleWorldX, 2) + Math.pow(y - handleWorldY, 2));
if (distance <= 200) {
isDragging = true;
dragStartY = y;
}
}
};
game.move = function (x, y, obj) {
if (isDragging && !isShifting && !isAnimating) {
var dragDistance = y - dragStartY;
// If dragged down enough, trigger lever pull
if (dragDistance > dragThreshold) {
lever.pull();
isDragging = false; // Prevent multiple triggers during same drag
}
}
};
game.up = function (x, y, obj) {
isDragging = false;
// Only allow lever handle to return up when touch is released
if (lever.isPulled) {
// Animate lever handle back up when released - much faster
tween(lever.leverHandle, {
y: -700
}, {
duration: 30,
easing: tween.easeOut,
onFinish: function onFinish() {
// Play lever release sound when handle reaches top
LK.getSound('leverRelease').play();
// Clear all cells first
for (var i = dropItems.length - 1; i >= 0; i--) {
var shape = dropItems[i];
shape.destroy();
dropItems.splice(i, 1);
}
// Reset isFromScore flag for all items when slot is pulled
if (currentInventoryItem) {
currentInventoryItem.isFromScore = false;
}
for (var i = 0; i < goodsGrid.length; i++) {
if (goodsGrid[i] !== null) {
goodsGrid[i].isFromScore = false;
}
}
// Start spawning immediately after clearing
spawnShapes();
}
});
lever.isPulled = false;
}
};
game.update = function () {
cleanupOffscreenShapes();
// Keep lever handle always active - no passive state
};
updateScore();
function checkColumnsForMatches(callback) {
// Check all columns from left to right (column 0 to 3)
checkColumnMatches(0, callback);
}
function checkColumnMatches(targetColumn, callback) {
if (targetColumn >= 4) {
// All columns checked, call final callback
if (callback) callback();
return;
}
// Get all shapes in the target column
var columnShapes = [];
for (var i = 0; i < dropItems.length; i++) {
if (dropItems[i].lane === targetColumn) {
columnShapes.push(dropItems[i]);
}
}
if (columnShapes.length < 2) {
// Move to next column
checkColumnMatches(targetColumn + 1, callback);
return;
}
// Count identical shapes (same shapeType) in this column
var shapeTypeCount = {};
for (var i = 0; i < columnShapes.length; i++) {
var shape = columnShapes[i];
shapeTypeCount[shape.shapeType] = (shapeTypeCount[shape.shapeType] || 0) + 1;
}
// Find all matching groups in this column
var matchingGroups = [];
for (var key in shapeTypeCount) {
if (shapeTypeCount[key] === 4) {
matchingGroups.push({
type: key,
count: 4,
points: 500
});
} else if (shapeTypeCount[key] === 3) {
matchingGroups.push({
type: key,
count: 3,
points: 250
});
} else if (shapeTypeCount[key] === 2) {
matchingGroups.push({
type: key,
count: 2,
points: 50
});
}
}
if (matchingGroups.length > 0) {
// Process each matching group sequentially for this column
processMatchingGroups(matchingGroups, columnShapes, 0, function () {
// After processing this column, move to next column
checkColumnMatches(targetColumn + 1, callback);
});
} else {
// No match in this column, move to next column
checkColumnMatches(targetColumn + 1, callback);
}
}
Corn. In-Game asset. 2d. High contrast. No shadows
Green apple. In-Game asset. 2d. High contrast. No shadows
Grape. In-Game asset. 2d. High contrast. No shadows
Green grape. In-Game asset. 2d. High contrast. No shadows
ekmek. In-Game asset. 2d. High contrast. No shadows
peynir. In-Game asset. 2d. High contrast. No shadows
meat. In-Game asset. 2d. High contrast. No shadows
fish. In-Game asset. 2d. High contrast. No shadows
red apple. In-Game asset. 2d. High contrast. No shadows
orange. In-Game asset. 2d. High contrast. No shadows
3d gray ball shiny. In-Game asset. 2d. High contrast. No shadows
200x800 inset corners box gray shiny. In-Game asset. 2d. High contrast. No shadows