/****
* 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