/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Cell = Container.expand(function (row, col) {
var self = Container.call(this);
self.row = row;
self.col = col;
self.value = 0; // 0 = empty, 1 = X (blue), 2 = O (red)
var cellBg = self.attachAsset('cell', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.01 // Make almost invisible but still interactive
});
// Make the entire cell area interactive
self.interactive = true;
self.hitArea = new Rectangle(-290, -290, 580, 580);
self.marker = null;
// Add hover effect to show clickable area
self.move = function (x, y, obj) {
if (!gameReady || gameOver || self.value !== 0 || gameMode === 'menu') return;
if (isAIMode && currentPlayer !== 1) return;
cellBg.alpha = 0.2; // Show cell is hoverable
};
// Reset hover effect when mouse leaves
self.up = function (x, y, obj) {
if (self.value === 0) {
cellBg.alpha = 0.01; // Reset to almost invisible
}
};
self.placeMarker = function (type, callback) {
if (self.value !== 0) return false;
// Prevent placing marker if already has one or is animating
if (self.marker || self.value !== 0) return false;
// In AI mode, extra validation
if (isAIMode && type === 1 && aiProcessing) return false;
if (isAIMode && type === 2 && !aiProcessing) return false;
self.value = type;
// Get asset names based on current appearance style
var xAssetName, oAssetName;
if (currentAppearanceStyle === 0) {
xAssetName = 'xMarker';
oAssetName = 'oMarker';
} else if (currentAppearanceStyle === 1) {
xAssetName = 'xMarkerStyle1';
oAssetName = 'oMarkerStyle1';
} else if (currentAppearanceStyle === 2) {
xAssetName = 'xMarkerStyle2';
oAssetName = 'oMarkerStyle2';
} else if (currentAppearanceStyle === 3) {
xAssetName = 'xMarkerStyle3';
oAssetName = 'oMarkerStyle3';
} else if (currentAppearanceStyle === 4) {
xAssetName = 'xMarkerStyle4';
oAssetName = 'oMarkerStyle4';
} else if (currentAppearanceStyle === 5) {
xAssetName = 'xMarkerStyle5';
oAssetName = 'oMarkerStyle5';
} else if (currentAppearanceStyle === 6) {
xAssetName = 'xMarkerStyle6';
oAssetName = 'oMarkerStyle6';
}
if (type === 1) {
// Blue X
if (currentAppearanceStyle === 1) {
// Style 1: Blue square for X
self.marker = self.attachAsset('xMarkerStyle1', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
});
tween(self.marker, {
alpha: 0.9,
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 300,
easing: tween.easeOut,
onFinish: callback
});
} else if (currentAppearanceStyle === 2) {
// Style 2: Purple square for X
self.marker = self.attachAsset('xMarkerStyle2', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
});
tween(self.marker, {
alpha: 0.9,
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 300,
easing: tween.easeOut,
onFinish: callback
});
} else if (currentAppearanceStyle === 3) {
// Style 3: Pink square for X
self.marker = self.attachAsset('xMarkerStyle3', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
});
tween(self.marker, {
alpha: 0.9,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 300,
easing: tween.easeOut,
onFinish: callback
});
} else if (currentAppearanceStyle === 4) {
// Style 4: Ronaldo for X
self.marker = self.attachAsset('xMarkerStyle4', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
});
tween(self.marker, {
alpha: 0.9,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 300,
easing: tween.easeOut,
onFinish: callback
});
} else if (currentAppearanceStyle === 5) {
// Style 5: Spiderman for X
self.marker = self.attachAsset('xMarkerStyle5', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
});
tween(self.marker, {
alpha: 0.9,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 300,
easing: tween.easeOut,
onFinish: callback
});
} else if (currentAppearanceStyle === 6) {
// Style 6: Steve for X
self.marker = self.attachAsset('xMarkerStyle6', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
});
tween(self.marker, {
alpha: 0.9,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 300,
easing: tween.easeOut,
onFinish: callback
});
} else {
// Standard X marker (style 0)
self.marker = self.attachAsset(xAssetName, {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
});
tween(self.marker, {
alpha: 0.9,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 300,
easing: tween.easeOut,
onFinish: callback
});
}
} else {
// Red O
if (currentAppearanceStyle === 1) {
// Style 1: Red square for O
self.marker = self.attachAsset('oMarkerStyle1', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
});
tween(self.marker, {
alpha: 0.9,
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 300,
easing: tween.easeOut,
onFinish: callback
});
} else if (currentAppearanceStyle === 2) {
// Style 2: Orange square for O
self.marker = self.attachAsset('oMarkerStyle2', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
});
tween(self.marker, {
alpha: 0.9,
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 300,
easing: tween.easeOut,
onFinish: callback
});
} else if (currentAppearanceStyle === 3) {
// Style 3: Green square for O
self.marker = self.attachAsset('oMarkerStyle3', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
});
tween(self.marker, {
alpha: 0.9,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 300,
easing: tween.easeOut,
onFinish: callback
});
} else if (currentAppearanceStyle === 4) {
// Style 4: Messi for O
self.marker = self.attachAsset('oMarkerStyle4', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
});
tween(self.marker, {
alpha: 0.9,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 300,
easing: tween.easeOut,
onFinish: callback
});
} else if (currentAppearanceStyle === 5) {
// Style 5: Venom for O
self.marker = self.attachAsset('oMarkerStyle5', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
});
tween(self.marker, {
alpha: 0.9,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 300,
easing: tween.easeOut,
onFinish: callback
});
} else if (currentAppearanceStyle === 6) {
// Style 6: Alex for O
self.marker = self.attachAsset('oMarkerStyle6', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
});
tween(self.marker, {
alpha: 0.9,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 300,
easing: tween.easeOut,
onFinish: callback
});
} else {
// Style 0: use original assets
self.marker = self.attachAsset(oAssetName, {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
});
tween(self.marker, {
alpha: 0.9,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 300,
easing: tween.easeOut,
onFinish: callback
});
}
}
LK.getSound('place').play();
return true;
};
self.down = function (x, y, obj) {
// Basic validation checks
if (!gameReady || gameOver || gameMode === 'menu') return;
if (self.value !== 0) return; // Cell already occupied
// Prevent placing markers when game board is not visible
if (gameBoard.alpha === 0) return;
// In AI mode, prevent ALL player input during AI processing or when it's not player's turn
if (isAIMode && (currentPlayer !== 1 || aiProcessing)) return;
// Additional safety check to prevent race conditions
if (isAIMode && currentPlayer === 2) return;
// Extra validation: ensure no other animations are running
if (isAIMode && aiProcessing) {
console.log("Player input blocked - AI is processing");
return;
}
// Check if any cell is currently animating to prevent interference
for (var r = 0; r < 3; r++) {
for (var c = 0; c < 3; c++) {
var checkCell = grid[r][c];
if (checkCell && checkCell.marker && checkCell.marker.alpha < 0.9 && checkCell.marker.alpha > 0) {
return; // Animation in progress, prevent input
}
}
}
// Place the marker with animation and wait for completion
if (self.placeMarker(currentPlayer, function () {
// This callback runs after the marker animation completes
checkWin();
if (!gameOver) {
if (isAIMode && currentPlayer === 1) {
// AI mode - player played, now AI plays
currentPlayer = 2;
updateTurnDisplay();
// Only start AI processing if not already processing
if (!aiProcessing) {
aiProcessing = true;
LK.setTimeout(function () {
if (!gameOver && currentPlayer === 2 && isAIMode) {
aiProcessing = false;
makeAIMove();
} else {
aiProcessing = false;
}
}, 100); // Small delay to ensure UI updates
}
} else if (isAIMode && currentPlayer === 2) {
// This shouldn't happen in AI mode since AI doesn't click
currentPlayer = 1;
updateTurnDisplay();
} else {
// Two player mode - switch players normally
currentPlayer = currentPlayer === 1 ? 2 : 1;
updateTurnDisplay();
}
}
})) {
// Marker placement started successfully - disable further input until animation completes
}
};
return self;
});
var WinLine = Container.expand(function () {
var self = Container.call(this);
self.line = self.attachAsset('winLine', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0,
scaleX: 0
});
self.showWinLine = function (startX, startY, endX, endY, color) {
var deltaX = endX - startX;
var deltaY = endY - startY;
var angle = Math.atan2(deltaY, deltaX);
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
self.x = startX + deltaX / 2;
self.y = startY + deltaY / 2;
self.line.rotation = angle;
self.line.tint = color;
self.line.width = distance;
tween(self.line, {
alpha: 1,
scaleX: 1
}, {
duration: 500,
easing: tween.easeOut
});
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a1a1a
});
/****
* Game Code
****/
// Alternative appearance styles
var grid = [];
var currentPlayer = 1; // 1 = Blue X, 2 = Red O
var gameOver = false;
var winLine = null;
var gameMode = 'menu'; // 'menu', 'ai', 'twoPlayer', 'difficulty'
var isAIMode = false;
var aiDifficulty = 'normal'; // 'easy', 'normal', 'hard'
var aiProcessing = false; // Flag to prevent AI from interfering with player moves
var currentLanguage = storage.language || 'tr'; // 'tr' for Turkish, 'en' for English
// Initialize appearance style from storage - default to normal X and O style
var currentAppearanceStyle = storage.appearanceStyle !== undefined ? storage.appearanceStyle : 0; // 0-3 for different X/O styles, start with 0 (normal X and O)
// Initialize statistics from storage with defaults
var gameStats = {
blueWins: storage.blueWins || 0,
redWins: storage.redWins || 0,
draws: storage.draws || 0
};
var selectedDifficulty = ''; // Store selected difficulty for confirmation
var isResetConfirmation = false; // Track if we're in reset confirmation mode
var languageTexts = {
tr: {
blueTurn: 'Sıra: Zeus',
redTurn: 'Sıra: HADES',
blueWin: 'ZEUS KAZANDI!',
redWin: 'HADES KAZANDI!',
draw: 'BERABERE!',
playAgain: 'Tekrar Oyna',
language: 'Türkçe',
vsAI: 'Yapay Zeka ile Oyna',
twoPlayer: 'İki Kişilik Oyna',
selectMode: 'Oyun Modunu Seçin',
back: '← Geri',
exit: 'Çıkış',
selectDifficulty: 'Zorluk Seçin',
easy: 'Kolay',
normal: 'Normal',
hard: 'Zor',
confirmEasy: 'Kolay modu seçmek istiyor musunuz?',
confirmNormal: 'Normal modu seçmek istiyor musunuz?',
confirmHard: 'Zor modu seçmek istiyor musunuz?',
yes: 'Evet',
no: 'Hayır',
blueWins: 'ZEUS Galibiyetler: ',
redWins: 'HADES Galibiyetler: ',
draws: 'Beraberlikler: ',
resetStats: 'İstatistikleri Sıfırla',
confirmReset: 'İstatistikleri sıfırlamaktan emin misiniz?',
settings: 'Ayarlar',
changeAppearance: 'Görünümü Değiştir',
selectPackage: 'Paket Seçin',
package1: 'Klasik X-O',
package2: 'Tom ve Jerry',
package3: 'Batman vs Joker',
package4: 'Ronaldo vs. Messi',
package5: 'Spiderman vs Venom',
package6: 'Steve vs Alex',
package7: 'Belirsiz',
selected: 'Seçili: '
},
en: {
blueTurn: 'Turn: Blue',
redTurn: 'Turn: HADES',
blueWin: 'ZEUS WON!',
redWin: 'HADES WON!',
draw: 'DRAW!',
playAgain: 'Play Again',
language: 'English',
vsAI: 'Play vs AI',
twoPlayer: 'Two Player',
selectMode: 'Select Game Mode',
back: '← Back',
exit: 'Exit',
selectDifficulty: 'Select Difficulty',
easy: 'Easy',
normal: 'Normal',
hard: 'Hard',
confirmEasy: 'Do you want to select Easy mode?',
confirmNormal: 'Do you want to select Normal mode?',
confirmHard: 'Do you want to select Hard mode?',
yes: 'Yes',
no: 'No',
blueWins: 'ZEUS Wins: ',
redWins: 'HADES Wins: ',
draws: 'Draws: ',
resetStats: 'Reset Statistics',
confirmReset: 'Are you sure you want to reset statistics?',
settings: 'Settings',
changeAppearance: 'Change Appearance',
selectPackage: 'Select Package',
package1: 'Classic X-O',
package2: 'Tom ve Jerry',
package3: 'Batman vs Joker',
package4: 'Ronaldo vs. Messi',
package5: 'Spiderman vs Venom',
package6: 'Steve vs Alex',
package7: 'Belirsiz',
selected: 'Selected: '
}
};
// Game setup
var gameBoard = game.addChild(new Container());
gameBoard.x = 2048 / 2;
gameBoard.y = 2732 / 2;
gameBoard.scaleX = 1.2;
gameBoard.scaleY = 1.2;
gameBoard.alpha = 0; // Hidden initially
// Create background
var background = gameBoard.attachAsset('gridBackground', {
anchorX: 0.5,
anchorY: 0.5
});
// Create grid lines
var verticalLine1 = gameBoard.attachAsset('gridLine', {
anchorX: 0.5,
anchorY: 0.5,
x: -300,
height: 1800
});
var verticalLine2 = gameBoard.attachAsset('gridLine', {
anchorX: 0.5,
anchorY: 0.5,
x: 300,
height: 1800
});
var horizontalLine1 = gameBoard.attachAsset('gridLine', {
anchorX: 0.5,
anchorY: 0.5,
y: -300,
width: 1800,
height: 8
});
var horizontalLine2 = gameBoard.attachAsset('gridLine', {
anchorX: 0.5,
anchorY: 0.5,
y: 300,
width: 1800,
height: 8
});
// Create cells
for (var row = 0; row < 3; row++) {
grid[row] = [];
for (var col = 0; col < 3; col++) {
var cell = gameBoard.addChild(new Cell(row, col));
cell.x = (col - 1) * 600;
cell.y = (row - 1) * 600;
grid[row][col] = cell;
}
}
// UI Elements
var blueTurnText = new Text2(languageTexts[currentLanguage].blueTurn, {
size: 100,
fill: 0x00AAFF
});
blueTurnText.anchor.set(0.5, 0);
LK.gui.top.addChild(blueTurnText);
blueTurnText.y = 220;
var redTurnText = new Text2(languageTexts[currentLanguage].redTurn, {
size: 100,
fill: 0xff0000
});
redTurnText.anchor.set(0.5, 0);
LK.gui.top.addChild(redTurnText);
redTurnText.y = 220;
var languageBtn = new Text2(languageTexts[currentLanguage === 'tr' ? 'en' : 'tr'].language, {
size: 60,
fill: 0xFFFFFF
});
languageBtn.anchor.set(0.5, 0);
LK.gui.top.addChild(languageBtn);
languageBtn.y = 120;
var statusText = new Text2('', {
size: 100,
fill: 0xFFFFFF
});
statusText.anchor.set(0.5, 0.5);
LK.gui.center.addChild(statusText);
statusText.y = 400;
// Create background for play again button
var playAgainBg = LK.getAsset('cell', {
anchorX: 0.5,
anchorY: 0.5,
width: 500,
height: 120,
tint: 0x4CAF50,
alpha: 0
});
LK.gui.center.addChild(playAgainBg);
playAgainBg.y = 550;
var playAgainBtn = new Text2(languageTexts[currentLanguage].playAgain, {
size: 90,
fill: 0xFFFFFF
});
playAgainBtn.anchor.set(0.5, 0.5);
playAgainBtn.interactive = false;
playAgainBtn.hitArea = new Rectangle(-250, -60, 500, 120);
LK.gui.center.addChild(playAgainBtn);
playAgainBtn.y = 550;
playAgainBtn.alpha = 0;
// Settings button
var settingsBtn = new Text2(languageTexts[currentLanguage].settings, {
size: 80,
fill: 0xFFAA00
});
settingsBtn.anchor.set(0.5, 0.5);
settingsBtn.interactive = false;
settingsBtn.hitArea = new Rectangle(-100, -40, 200, 80);
LK.gui.center.addChild(settingsBtn);
settingsBtn.y = -300;
// Menu UI elements
var menuTitle = new Text2(languageTexts[currentLanguage].selectMode, {
size: 120,
fill: 0xFFFFFF
});
menuTitle.anchor.set(0.5, 0.5);
LK.gui.center.addChild(menuTitle);
menuTitle.y = -200;
// AI Difficulty selection elements
var difficultyTitle = new Text2(languageTexts[currentLanguage].selectDifficulty, {
size: 100,
fill: 0xFFFFFF
});
difficultyTitle.anchor.set(0.5, 0.5);
LK.gui.center.addChild(difficultyTitle);
difficultyTitle.y = -200;
difficultyTitle.alpha = 0;
// Create background blocks for difficulty buttons
var easyBlock = LK.getAsset('cell', {
anchorX: 0.5,
anchorY: 0.5,
width: 400,
height: 120,
tint: 0x44FF44,
alpha: 0.3
});
LK.gui.center.addChild(easyBlock);
easyBlock.y = -100;
easyBlock.alpha = 0;
var normalBlock = LK.getAsset('cell', {
anchorX: 0.5,
anchorY: 0.5,
width: 400,
height: 120,
tint: 0xFFAA00,
alpha: 0.3
});
LK.gui.center.addChild(normalBlock);
normalBlock.y = 50;
normalBlock.alpha = 0;
var hardBlock = LK.getAsset('cell', {
anchorX: 0.5,
anchorY: 0.5,
width: 400,
height: 120,
tint: 0xFF4444,
alpha: 0.3
});
LK.gui.center.addChild(hardBlock);
hardBlock.y = 200;
hardBlock.alpha = 0;
var easyBtn = new Text2(languageTexts[currentLanguage].easy, {
size: 90,
fill: 0x44FF44
});
easyBtn.anchor.set(0.5, 0.5);
easyBtn.interactive = false;
easyBtn.hitArea = new Rectangle(-150, -45, 300, 90);
LK.gui.center.addChild(easyBtn);
easyBtn.y = -100;
easyBtn.alpha = 0;
var normalBtn = new Text2(languageTexts[currentLanguage].normal, {
size: 90,
fill: 0xFFAA00
});
normalBtn.anchor.set(0.5, 0.5);
normalBtn.interactive = false;
normalBtn.hitArea = new Rectangle(-150, -45, 300, 90);
LK.gui.center.addChild(normalBtn);
normalBtn.y = 50;
normalBtn.alpha = 0;
var hardBtn = new Text2(languageTexts[currentLanguage].hard, {
size: 90,
fill: 0xFF4444
});
hardBtn.anchor.set(0.5, 0.5);
hardBtn.interactive = false;
hardBtn.hitArea = new Rectangle(-150, -45, 300, 90);
LK.gui.center.addChild(hardBtn);
hardBtn.y = 200;
hardBtn.alpha = 0;
// Confirmation dialog elements
var confirmationBg = LK.getAsset('gridBackground', {
anchorX: 0.5,
anchorY: 0.5,
width: 1200,
height: 600,
tint: 0x000000,
alpha: 0.8
});
LK.gui.center.addChild(confirmationBg);
confirmationBg.alpha = 0;
var confirmationText = new Text2('', {
size: 80,
fill: 0xFFFFFF
});
confirmationText.anchor.set(0.5, 0.5);
LK.gui.center.addChild(confirmationText);
confirmationText.y = -50;
confirmationText.alpha = 0;
var yesBtn = new Text2(languageTexts[currentLanguage].yes, {
size: 80,
fill: 0x44FF44
});
yesBtn.anchor.set(0.5, 0.5);
yesBtn.interactive = true;
LK.gui.center.addChild(yesBtn);
yesBtn.x = -150;
yesBtn.y = 100;
yesBtn.alpha = 0;
var noBtn = new Text2(languageTexts[currentLanguage].no, {
size: 80,
fill: 0xFF4444
});
noBtn.anchor.set(0.5, 0.5);
noBtn.interactive = true;
LK.gui.center.addChild(noBtn);
noBtn.x = 150;
noBtn.y = 100;
noBtn.alpha = 0;
// Add hit areas to confirmation dialog buttons
yesBtn.hitArea = new Rectangle(-100, -40, 200, 80);
noBtn.hitArea = new Rectangle(-100, -40, 200, 80);
// Confirmation dialog button handlers
yesBtn.down = function (x, y, obj) {
if (isResetConfirmation) {
// Reset all statistics to zero
gameStats.blueWins = 0;
gameStats.redWins = 0;
gameStats.draws = 0;
// Update storage
storage.blueWins = 0;
storage.redWins = 0;
storage.draws = 0;
// Update display
blueStatsText.setText(languageTexts[currentLanguage].blueWins + gameStats.blueWins);
redStatsText.setText(languageTexts[currentLanguage].redWins + gameStats.redWins);
drawStatsText.setText(languageTexts[currentLanguage].draws + gameStats.draws);
hideConfirmationDialog();
} else if (selectedDifficulty) {
aiDifficulty = selectedDifficulty;
hideConfirmationDialog();
startGame('ai');
}
};
noBtn.down = function (x, y, obj) {
hideConfirmationDialog();
};
// Add glowing animation to blocks
function animateDifficultyBlocks() {
tween(easyBlock, {
alpha: 0.6
}, {
duration: 1000,
easing: tween.easeInOut,
repeat: -1,
yoyo: true
});
tween(normalBlock, {
alpha: 0.6
}, {
duration: 1000,
easing: tween.easeInOut,
repeat: -1,
yoyo: true,
delay: 333
});
tween(hardBlock, {
alpha: 0.6
}, {
duration: 1000,
easing: tween.easeInOut,
repeat: -1,
yoyo: true,
delay: 666
});
}
function showConfirmationDialog(difficulty) {
selectedDifficulty = difficulty;
gameMode = 'confirmation';
isResetConfirmation = false;
var confirmText = '';
if (difficulty === 'easy') {
confirmText = languageTexts[currentLanguage].confirmEasy;
} else if (difficulty === 'normal') {
confirmText = languageTexts[currentLanguage].confirmNormal;
} else if (difficulty === 'hard') {
confirmText = languageTexts[currentLanguage].confirmHard;
}
confirmationText.setText(confirmText);
// Enable confirmation button interactions
yesBtn.interactive = true;
noBtn.interactive = true;
// Show confirmation elements
tween(confirmationBg, {
alpha: 0.8
}, {
duration: 200
});
tween(confirmationText, {
alpha: 1
}, {
duration: 200
});
tween(yesBtn, {
alpha: 1
}, {
duration: 200
});
tween(noBtn, {
alpha: 1
}, {
duration: 200
});
}
function showResetConfirmationDialog() {
isResetConfirmation = true;
gameMode = 'confirmation';
selectedDifficulty = '';
confirmationText.setText(languageTexts[currentLanguage].confirmReset);
// Enable confirmation button interactions
yesBtn.interactive = true;
noBtn.interactive = true;
// Show confirmation elements
tween(confirmationBg, {
alpha: 0.8
}, {
duration: 200
});
tween(confirmationText, {
alpha: 1
}, {
duration: 200
});
tween(yesBtn, {
alpha: 1
}, {
duration: 200
});
tween(noBtn, {
alpha: 1
}, {
duration: 200
});
}
function hideConfirmationDialog() {
if (isResetConfirmation) {
// Return to appropriate game mode when hiding reset confirmation
if (gameBoard.alpha > 0) {
gameMode = isAIMode ? 'ai' : 'twoPlayer';
} else {
gameMode = 'menu';
}
} else {
gameMode = 'difficulty';
}
selectedDifficulty = '';
isResetConfirmation = false;
// Disable confirmation button interactions
yesBtn.interactive = false;
noBtn.interactive = false;
// Hide confirmation elements
tween(confirmationBg, {
alpha: 0
}, {
duration: 200
});
tween(confirmationText, {
alpha: 0
}, {
duration: 200
});
tween(yesBtn, {
alpha: 0
}, {
duration: 200
});
tween(noBtn, {
alpha: 0
}, {
duration: 200
});
}
var vsAIBtn = new Text2(languageTexts[currentLanguage].vsAI, {
size: 100,
fill: 0x00AAFF
});
vsAIBtn.anchor.set(0.5, 0.5);
vsAIBtn.interactive = false;
vsAIBtn.hitArea = new Rectangle(-200, -50, 400, 100);
LK.gui.center.addChild(vsAIBtn);
vsAIBtn.y = 0;
var twoPlayerBtn = new Text2(languageTexts[currentLanguage].twoPlayer, {
size: 100,
fill: 0xFF4444
});
twoPlayerBtn.anchor.set(0.5, 0.5);
twoPlayerBtn.interactive = false;
twoPlayerBtn.hitArea = new Rectangle(-200, -50, 400, 100);
LK.gui.center.addChild(twoPlayerBtn);
twoPlayerBtn.y = 150;
var backBtn = new Text2(languageTexts[currentLanguage].back, {
size: 70,
fill: 0xFFFFFF
});
backBtn.anchor.set(0.5, 0.5);
backBtn.interactive = false;
backBtn.hitArea = new Rectangle(-150, -40, 300, 80);
LK.gui.top.addChild(backBtn);
backBtn.x = 200;
backBtn.y = 220;
backBtn.alpha = 0;
var exitBtn = new Text2(languageTexts[currentLanguage].exit, {
size: 60,
fill: 0xFF0000
});
exitBtn.anchor.set(0.5, 0);
exitBtn.interactive = false;
exitBtn.hitArea = new Rectangle(-80, -30, 160, 60);
LK.gui.top.addChild(exitBtn);
exitBtn.y = 120;
exitBtn.x = 400;
exitBtn.alpha = 0;
// Statistics display elements
var statsContainer = new Container();
LK.gui.bottom.addChild(statsContainer);
statsContainer.y = -180;
statsContainer.alpha = 0;
var blueStatsText = new Text2(languageTexts[currentLanguage].blueWins + gameStats.blueWins, {
size: 45,
fill: 0x00AAFF
});
blueStatsText.anchor.set(0.5, 0);
statsContainer.addChild(blueStatsText);
blueStatsText.y = 0;
blueStatsText.x = -600;
var redStatsText = new Text2(languageTexts[currentLanguage].redWins + gameStats.redWins, {
size: 45,
fill: 0xFF4444
});
redStatsText.anchor.set(0.5, 0);
statsContainer.addChild(redStatsText);
redStatsText.y = 0;
redStatsText.x = 0;
var drawStatsText = new Text2(languageTexts[currentLanguage].draws + gameStats.draws, {
size: 45,
fill: 0xFFFFFF
});
drawStatsText.anchor.set(0.5, 0);
statsContainer.addChild(drawStatsText);
drawStatsText.y = 0;
drawStatsText.x = 600;
var resetStatsBtn = new Text2(languageTexts[currentLanguage].resetStats, {
size: 40,
fill: 0xFF4444
});
resetStatsBtn.anchor.set(0.5, 0);
resetStatsBtn.interactive = true;
resetStatsBtn.hitArea = new Rectangle(-70, -20, 140, 40);
statsContainer.addChild(resetStatsBtn);
resetStatsBtn.y = 70;
resetStatsBtn.x = 0;
// Change Appearance button
var changeAppearanceBtn = new Text2(languageTexts[currentLanguage].changeAppearance, {
size: 60,
fill: 0x00AAFF
});
changeAppearanceBtn.anchor.set(0.5, 0.5);
changeAppearanceBtn.interactive = true;
changeAppearanceBtn.hitArea = new Rectangle(-120, -30, 240, 60);
LK.gui.center.addChild(changeAppearanceBtn);
changeAppearanceBtn.y = -100;
changeAppearanceBtn.alpha = 0;
// Current appearance style display
var currentStyleText = new Text2('', {
size: 50,
fill: 0xFFFFFF
});
currentStyleText.anchor.set(0.5, 0.5);
LK.gui.center.addChild(currentStyleText);
currentStyleText.y = -20;
currentStyleText.alpha = 0;
// Package selection UI elements
var packageTitle = new Text2(languageTexts[currentLanguage].selectPackage, {
size: 100,
fill: 0xFFFFFF
});
packageTitle.anchor.set(0.5, 0.5);
LK.gui.center.addChild(packageTitle);
packageTitle.y = -250;
packageTitle.alpha = 0;
// Package selection buttons
var package1Btn = new Text2(languageTexts[currentLanguage].package1, {
size: 80,
fill: 0x00AAFF
});
package1Btn.anchor.set(0.5, 0.5);
package1Btn.interactive = false;
package1Btn.hitArea = new Rectangle(-120, -40, 240, 80);
LK.gui.center.addChild(package1Btn);
package1Btn.y = -120;
package1Btn.alpha = 0;
var package2Btn = new Text2(languageTexts[currentLanguage].package2, {
size: 80,
fill: 0xFF8800
});
package2Btn.anchor.set(0.5, 0.5);
package2Btn.interactive = false;
package2Btn.hitArea = new Rectangle(-120, -40, 240, 80);
LK.gui.center.addChild(package2Btn);
package2Btn.y = -20;
package2Btn.alpha = 0;
var package3Btn = new Text2(languageTexts[currentLanguage].package3, {
size: 80,
fill: 0x44FF44
});
package3Btn.anchor.set(0.5, 0.5);
package3Btn.interactive = false;
package3Btn.hitArea = new Rectangle(-120, -40, 240, 80);
LK.gui.center.addChild(package3Btn);
package3Btn.y = 80;
package3Btn.alpha = 0;
var package4Btn = new Text2(languageTexts[currentLanguage].package4, {
size: 80,
fill: 0xFF4444
});
package4Btn.anchor.set(0.5, 0.5);
package4Btn.interactive = false;
package4Btn.hitArea = new Rectangle(-120, -40, 240, 80);
LK.gui.center.addChild(package4Btn);
package4Btn.y = 180;
package4Btn.alpha = 0;
var package5Btn = new Text2(languageTexts[currentLanguage].package5, {
size: 80,
fill: 0x00FFFF
});
package5Btn.anchor.set(0.5, 0.5);
package5Btn.interactive = false;
package5Btn.hitArea = new Rectangle(-120, -40, 240, 80);
LK.gui.center.addChild(package5Btn);
package5Btn.y = 280;
package5Btn.alpha = 0;
var package6Btn = new Text2(languageTexts[currentLanguage].package6, {
size: 80,
fill: 0xFF00FF
});
package6Btn.anchor.set(0.5, 0.5);
package6Btn.interactive = false;
package6Btn.hitArea = new Rectangle(-120, -40, 240, 80);
LK.gui.center.addChild(package6Btn);
package6Btn.y = 380;
package6Btn.alpha = 0;
var package7Btn = new Text2(languageTexts[currentLanguage].package7, {
size: 80,
fill: 0x00FF00
});
package7Btn.anchor.set(0.5, 0.5);
package7Btn.interactive = false;
package7Btn.hitArea = new Rectangle(-120, -40, 240, 80);
LK.gui.center.addChild(package7Btn);
package7Btn.y = 480;
package7Btn.alpha = 0;
// Package selection backgrounds
var package1Bg = LK.getAsset('cell', {
anchorX: 0.5,
anchorY: 0.5,
width: 300,
height: 80,
tint: 0x00AAFF,
alpha: 0.2
});
LK.gui.center.addChild(package1Bg);
package1Bg.y = -120;
package1Bg.alpha = 0;
var package2Bg = LK.getAsset('cell', {
anchorX: 0.5,
anchorY: 0.5,
width: 300,
height: 80,
tint: 0xFF8800,
alpha: 0.2
});
LK.gui.center.addChild(package2Bg);
package2Bg.y = -20;
package2Bg.alpha = 0;
var package3Bg = LK.getAsset('cell', {
anchorX: 0.5,
anchorY: 0.5,
width: 300,
height: 80,
tint: 0x44FF44,
alpha: 0.2
});
LK.gui.center.addChild(package3Bg);
package3Bg.y = 80;
package3Bg.alpha = 0;
var package4Bg = LK.getAsset('cell', {
anchorX: 0.5,
anchorY: 0.5,
width: 300,
height: 80,
tint: 0xFF4444,
alpha: 0.2
});
LK.gui.center.addChild(package4Bg);
package4Bg.y = 180;
package4Bg.alpha = 0;
var package5Bg = LK.getAsset('cell', {
anchorX: 0.5,
anchorY: 0.5,
width: 300,
height: 80,
tint: 0x00FFFF,
alpha: 0.2
});
LK.gui.center.addChild(package5Bg);
package5Bg.y = 280;
package5Bg.alpha = 0;
var package6Bg = LK.getAsset('cell', {
anchorX: 0.5,
anchorY: 0.5,
width: 300,
height: 80,
tint: 0xFF00FF,
alpha: 0.2
});
LK.gui.center.addChild(package6Bg);
package6Bg.y = 380;
package6Bg.alpha = 0;
var package7Bg = LK.getAsset('cell', {
anchorX: 0.5,
anchorY: 0.5,
width: 300,
height: 80,
tint: 0x00FF00,
alpha: 0.2
});
LK.gui.center.addChild(package7Bg);
package7Bg.y = 480;
package7Bg.alpha = 0;
// Language toggle functionality
languageBtn.interactive = true; // Always interactive
languageBtn.hitArea = new Rectangle(-100, -40, 200, 80);
languageBtn.down = function (x, y, obj) {
// Always allow language switching regardless of game state
currentLanguage = currentLanguage === 'tr' ? 'en' : 'tr';
storage.language = currentLanguage;
updateLanguageTexts();
};
// Menu button handlers
vsAIBtn.down = function (x, y, obj) {
if (gameMode === 'menu') {
showDifficultySelection();
}
};
twoPlayerBtn.down = function (x, y, obj) {
if (gameMode === 'menu') {
startGame('twoPlayer');
}
};
// Difficulty button handlers
easyBtn.down = function (x, y, obj) {
if (gameMode === 'difficulty') {
showConfirmationDialog('easy');
}
};
normalBtn.down = function (x, y, obj) {
if (gameMode === 'difficulty') {
showConfirmationDialog('normal');
}
};
hardBtn.down = function (x, y, obj) {
if (gameMode === 'difficulty') {
showConfirmationDialog('hard');
}
};
backBtn.down = function (x, y, obj) {
if (gameMode === 'confirmation') {
hideConfirmationDialog();
} else if (gameMode === 'difficulty') {
showMenu();
} else if (gameMode === 'settings') {
showMenu();
} else if (gameMode === 'packages') {
showSettingsMenu();
} else if (gameMode !== 'menu') {
resetGame();
showMenu();
}
};
exitBtn.down = function (x, y, obj) {
if (gameMode !== 'menu') {
resetGame();
showMenu();
}
};
resetStatsBtn.down = function (x, y, obj) {
if (statsContainer.alpha > 0) {
// Show reset confirmation dialog
showResetConfirmationDialog();
}
};
changeAppearanceBtn.down = function (x, y, obj) {
if (gameMode === 'settings') {
showPackageSelection();
}
};
// Package selection button handlers
package1Btn.down = function (x, y, obj) {
if (gameMode === 'packages') {
selectPackage(0);
}
};
package2Btn.down = function (x, y, obj) {
if (gameMode === 'packages') {
selectPackage(1);
}
};
package3Btn.down = function (x, y, obj) {
if (gameMode === 'packages') {
selectPackage(2);
}
};
package4Btn.down = function (x, y, obj) {
if (gameMode === 'packages') {
selectPackage(3);
}
};
package5Btn.down = function (x, y, obj) {
if (gameMode === 'packages') {
selectPackage(4);
}
};
package6Btn.down = function (x, y, obj) {
if (gameMode === 'packages') {
selectPackage(5);
}
};
package7Btn.down = function (x, y, obj) {
if (gameMode === 'packages') {
selectPackage(6);
}
};
settingsBtn.down = function (x, y, obj) {
if (gameMode === 'menu') {
showSettingsMenu();
}
};
function showPackageSelection() {
gameMode = 'packages';
// Hide settings menu
changeAppearanceBtn.alpha = 0;
changeAppearanceBtn.interactive = false;
// Hide current style text
currentStyleText.alpha = 0;
// Show package selection elements
packageTitle.alpha = 1;
package1Btn.alpha = 1;
package2Btn.alpha = 1;
package3Btn.alpha = 1;
package4Btn.alpha = 1;
package5Btn.alpha = 1;
package6Btn.alpha = 1;
package7Btn.alpha = 1;
package1Bg.alpha = 0.2;
package2Bg.alpha = 0.2;
package3Bg.alpha = 0.2;
package4Bg.alpha = 0.2;
package5Bg.alpha = 0.2;
package6Bg.alpha = 0.2;
package7Bg.alpha = 0.2;
// Enable package button interactions
package1Btn.interactive = true;
package2Btn.interactive = true;
package3Btn.interactive = true;
package4Btn.interactive = true;
package5Btn.interactive = true;
package6Btn.interactive = true;
package7Btn.interactive = true;
// Highlight current package
highlightCurrentPackage();
}
function selectPackage(packageIndex) {
currentAppearanceStyle = packageIndex;
storage.appearanceStyle = currentAppearanceStyle;
// If there's an active game, reset it to apply new styles
if (gameBoard.alpha > 0) {
resetGame();
}
// Update package highlight
highlightCurrentPackage();
// Go back to settings menu after selection
showSettingsMenu();
}
function highlightCurrentPackage() {
// Reset all backgrounds
package1Bg.alpha = 0.2;
package2Bg.alpha = 0.2;
package3Bg.alpha = 0.2;
package4Bg.alpha = 0.2;
package5Bg.alpha = 0.2;
package6Bg.alpha = 0.2;
package7Bg.alpha = 0.2;
// Highlight current selection
if (currentAppearanceStyle === 0) {
package1Bg.alpha = 0.6;
} else if (currentAppearanceStyle === 1) {
package2Bg.alpha = 0.6;
} else if (currentAppearanceStyle === 2) {
package3Bg.alpha = 0.6;
} else if (currentAppearanceStyle === 3) {
package4Bg.alpha = 0.6;
} else if (currentAppearanceStyle === 4) {
package5Bg.alpha = 0.6;
} else if (currentAppearanceStyle === 5) {
package6Bg.alpha = 0.6;
} else if (currentAppearanceStyle === 6) {
package7Bg.alpha = 0.6;
}
}
function updateLanguageTexts() {
blueTurnText.setText(languageTexts[currentLanguage].blueTurn);
redTurnText.setText(languageTexts[currentLanguage].redTurn);
playAgainBtn.setText(languageTexts[currentLanguage].playAgain);
languageBtn.setText(languageTexts[currentLanguage === 'tr' ? 'en' : 'tr'].language);
menuTitle.setText(languageTexts[currentLanguage].selectMode);
vsAIBtn.setText(languageTexts[currentLanguage].vsAI);
twoPlayerBtn.setText(languageTexts[currentLanguage].twoPlayer);
backBtn.setText(languageTexts[currentLanguage].back);
exitBtn.setText(languageTexts[currentLanguage].exit);
difficultyTitle.setText(languageTexts[currentLanguage].selectDifficulty);
easyBtn.setText(languageTexts[currentLanguage].easy);
normalBtn.setText(languageTexts[currentLanguage].normal);
hardBtn.setText(languageTexts[currentLanguage].hard);
yesBtn.setText(languageTexts[currentLanguage].yes);
noBtn.setText(languageTexts[currentLanguage].no);
settingsBtn.setText(languageTexts[currentLanguage].settings);
changeAppearanceBtn.setText(languageTexts[currentLanguage].changeAppearance);
packageTitle.setText(languageTexts[currentLanguage].selectPackage);
package1Btn.setText(languageTexts[currentLanguage].package1);
package2Btn.setText(languageTexts[currentLanguage].package2);
package3Btn.setText(languageTexts[currentLanguage].package3);
package4Btn.setText(languageTexts[currentLanguage].package4);
package5Btn.setText(languageTexts[currentLanguage].package5);
package6Btn.setText(languageTexts[currentLanguage].package6);
package7Btn.setText(languageTexts[currentLanguage].package7);
// Update winner/draw text if game is over
if (gameOver && statusText.alpha > 0) {
var currentText = statusText.text;
// Check for all possible winner texts based on styles
var isBlueWin = false;
var isRedWin = false;
var isDraw = false;
var isXWin = false;
var isOWin = false;
// Check classic wins
if (currentText === languageTexts.tr.blueWin || currentText === languageTexts.en.blueWin) isBlueWin = true;
if (currentText === languageTexts.tr.redWin || currentText === languageTexts.en.redWin) isRedWin = true;
if (currentText === languageTexts.tr.draw || currentText === languageTexts.en.draw) isDraw = true;
// Check Tom ve Jerry wins
if (currentText === 'TOM KAZANDI!' || currentText === 'TOM WON!') isXWin = true;
if (currentText === 'JERRY KAZANDI!' || currentText === 'JERRY WON!') isOWin = true;
// Check Batman vs Joker wins
if (currentText === 'BATMAN KAZANDI!' || currentText === 'BATMAN WON!') isXWin = true;
if (currentText === 'JOKER KAZANDI!' || currentText === 'JOKER WON!') isOWin = true;
// Check Ronaldo vs. Messi wins
if (currentText === 'RONALDO KAZANDI!' || currentText === 'RONALDO WON!') isXWin = true;
if (currentText === 'MESSI KAZANDI!' || currentText === 'MESSI WON!') isOWin = true;
// Check Spiderman vs Venom wins
if (currentText === 'SPIDERMAN KAZANDI!' || currentText === 'SPIDERMAN WON!') isXWin = true;
if (currentText === 'VENOM KAZANDI!' || currentText === 'VENOM WON!') isOWin = true;
// Check Steve vs Alex wins
if (currentText === 'STEVE KAZANDI!' || currentText === 'STEVE WON!') isXWin = true;
if (currentText === 'ALEX KAZANDI!' || currentText === 'ALEX WON!') isOWin = true;
// Update text based on current style and language
if (isBlueWin || isXWin) {
if (currentAppearanceStyle === 0) {
statusText.setText(languageTexts[currentLanguage].blueWin);
} else if (currentAppearanceStyle === 1) {
statusText.setText(currentLanguage === 'tr' ? 'TOM KAZANDI!' : 'TOM WON!');
} else if (currentAppearanceStyle === 2) {
statusText.setText(currentLanguage === 'tr' ? 'BATMAN KAZANDI!' : 'BATMAN WON!');
} else if (currentAppearanceStyle === 3) {
statusText.setText(currentLanguage === 'tr' ? 'RONALDO KAZANDI!' : 'RONALDO WON!');
} else if (currentAppearanceStyle === 4) {
statusText.setText(currentLanguage === 'tr' ? 'SPIDERMAN KAZANDI!' : 'SPIDERMAN WON!');
} else if (currentAppearanceStyle === 5) {
statusText.setText(currentLanguage === 'tr' ? 'STEVE KAZANDI!' : 'STEVE WON!');
} else if (currentAppearanceStyle === 6) {
statusText.setText(currentLanguage === 'tr' ? 'STEVE KAZANDI!' : 'STEVE WON!');
}
} else if (isRedWin || isOWin) {
if (currentAppearanceStyle === 0) {
statusText.setText(languageTexts[currentLanguage].redWin);
} else if (currentAppearanceStyle === 1) {
statusText.setText(currentLanguage === 'tr' ? 'JERRY KAZANDI!' : 'JERRY WON!');
} else if (currentAppearanceStyle === 2) {
statusText.setText(currentLanguage === 'tr' ? 'JOKER KAZANDI!' : 'JOKER WON!');
} else if (currentAppearanceStyle === 3) {
statusText.setText(currentLanguage === 'tr' ? 'MESSI KAZANDI!' : 'MESSI WON!');
} else if (currentAppearanceStyle === 4) {
statusText.setText(currentLanguage === 'tr' ? 'VENOM KAZANDI!' : 'VENOM WON!');
} else if (currentAppearanceStyle === 5) {
statusText.setText(currentLanguage === 'tr' ? 'ALEX KAZANDI!' : 'ALEX WON!');
} else if (currentAppearanceStyle === 6) {
statusText.setText(currentLanguage === 'tr' ? 'ALEX KAZANDI!' : 'ALEX WON!');
}
} else if (isDraw) {
statusText.setText(languageTexts[currentLanguage].draw);
}
}
// Update statistics display
blueStatsText.setText(languageTexts[currentLanguage].blueWins + gameStats.blueWins);
redStatsText.setText(languageTexts[currentLanguage].redWins + gameStats.redWins);
drawStatsText.setText(languageTexts[currentLanguage].draws + gameStats.draws);
resetStatsBtn.setText(languageTexts[currentLanguage].resetStats);
// Update current style text if visible
if (currentStyleText.alpha > 0) {
var currentStyleName = '';
if (currentAppearanceStyle === 0) {
currentStyleName = languageTexts[currentLanguage].package1;
} else if (currentAppearanceStyle === 1) {
currentStyleName = languageTexts[currentLanguage].package2;
} else if (currentAppearanceStyle === 2) {
currentStyleName = languageTexts[currentLanguage].package3;
} else if (currentAppearanceStyle === 3) {
currentStyleName = languageTexts[currentLanguage].package4;
} else if (currentAppearanceStyle === 4) {
currentStyleName = languageTexts[currentLanguage].package5;
} else if (currentAppearanceStyle === 5) {
currentStyleName = languageTexts[currentLanguage].package6;
} else if (currentAppearanceStyle === 6) {
currentStyleName = languageTexts[currentLanguage].package7;
}
currentStyleText.setText(languageTexts[currentLanguage].selected + currentStyleName);
}
// Reposition statistics horizontally to display side by side with better spacing
blueStatsText.y = 0;
blueStatsText.x = -500;
redStatsText.y = 0;
redStatsText.x = 0;
drawStatsText.y = 0;
drawStatsText.x = 500;
}
// Add logo in top-left corner
var logoImg = LK.getAsset('logo', {
anchorX: 0,
anchorY: 0,
scaleX: 0.5,
scaleY: 0.5
});
LK.gui.topLeft.addChild(logoImg);
logoImg.x = 120;
logoImg.y = 60;
// Add website text in the center
var websiteText = new Text2('vayabi.net', {
size: 80,
fill: 0xFFFFFF
});
websiteText.anchor.set(0.5, 0.5);
LK.gui.center.addChild(websiteText);
websiteText.y = 600;
websiteText.alpha = 0.7;
// Start in menu mode
showMenu();
function updateTurnDisplay() {
if (gameMode === 'menu' || gameOver) {
blueTurnText.alpha = 0;
redTurnText.alpha = 0;
} else if (currentPlayer === 1) {
blueTurnText.alpha = 1;
redTurnText.alpha = 0;
} else {
blueTurnText.alpha = 0;
redTurnText.alpha = 1;
}
}
function showMenu() {
gameMode = 'menu';
gameBoard.alpha = 0;
settingsBtn.alpha = 1;
settingsBtn.interactive = true;
menuTitle.alpha = 1;
vsAIBtn.alpha = 1;
twoPlayerBtn.alpha = 1;
// Enable main menu interactions
vsAIBtn.interactive = true;
twoPlayerBtn.interactive = true;
blueTurnText.alpha = 0;
redTurnText.alpha = 0;
statusText.alpha = 0;
playAgainBtn.alpha = 0;
playAgainBtn.interactive = false;
playAgainBg.alpha = 0;
backBtn.alpha = 0;
backBtn.interactive = false;
exitBtn.alpha = 0;
exitBtn.interactive = false;
// Hide difficulty selection
difficultyTitle.alpha = 0;
easyBtn.alpha = 0;
normalBtn.alpha = 0;
hardBtn.alpha = 0;
// Disable difficulty button interactions
easyBtn.interactive = false;
normalBtn.interactive = false;
hardBtn.interactive = false;
// Hide blocks
// Stop any active animations on difficulty blocks
tween.stop(easyBlock);
tween.stop(normalBlock);
tween.stop(hardBlock);
easyBlock.alpha = 0;
normalBlock.alpha = 0;
hardBlock.alpha = 0;
// Hide confirmation dialog
confirmationBg.alpha = 0;
confirmationText.alpha = 0;
yesBtn.alpha = 0;
noBtn.alpha = 0;
// Disable confirmation dialog interactions
yesBtn.interactive = false;
noBtn.interactive = false;
// Hide statistics in menu
statsContainer.alpha = 0;
// Hide appearance button
changeAppearanceBtn.alpha = 0;
changeAppearanceBtn.interactive = false;
// Hide current style text
currentStyleText.alpha = 0;
// Hide package selection elements
packageTitle.alpha = 0;
package1Btn.alpha = 0;
package2Btn.alpha = 0;
package3Btn.alpha = 0;
package4Btn.alpha = 0;
package5Btn.alpha = 0;
package6Btn.alpha = 0;
package7Btn.alpha = 0;
package1Bg.alpha = 0;
package2Bg.alpha = 0;
package3Bg.alpha = 0;
package4Bg.alpha = 0;
package5Bg.alpha = 0;
package6Bg.alpha = 0;
package7Bg.alpha = 0;
// Disable package button interactions
package1Btn.interactive = false;
package2Btn.interactive = false;
package3Btn.interactive = false;
package4Btn.interactive = false;
package5Btn.interactive = false;
package6Btn.interactive = false;
package7Btn.interactive = false;
}
function showSettingsMenu() {
gameMode = 'settings';
// Hide main menu
settingsBtn.alpha = 0;
settingsBtn.interactive = false;
menuTitle.alpha = 0;
vsAIBtn.alpha = 0;
twoPlayerBtn.alpha = 0;
vsAIBtn.interactive = false;
twoPlayerBtn.interactive = false;
// Show back button and language button more prominently
backBtn.alpha = 1;
backBtn.interactive = true;
// Show appearance change button
changeAppearanceBtn.alpha = 1;
changeAppearanceBtn.interactive = true;
// Show current appearance style
var currentStyleName = '';
if (currentAppearanceStyle === 0) {
currentStyleName = languageTexts[currentLanguage].package1;
} else if (currentAppearanceStyle === 1) {
currentStyleName = languageTexts[currentLanguage].package2;
} else if (currentAppearanceStyle === 2) {
currentStyleName = languageTexts[currentLanguage].package3;
} else if (currentAppearanceStyle === 3) {
currentStyleName = languageTexts[currentLanguage].package4;
} else if (currentAppearanceStyle === 4) {
currentStyleName = languageTexts[currentLanguage].package5;
} else if (currentAppearanceStyle === 5) {
currentStyleName = languageTexts[currentLanguage].package6;
} else if (currentAppearanceStyle === 6) {
currentStyleName = languageTexts[currentLanguage].package7;
}
currentStyleText.setText(languageTexts[currentLanguage].selected + currentStyleName);
currentStyleText.alpha = 1;
// Hide package selection elements
packageTitle.alpha = 0;
package1Btn.alpha = 0;
package2Btn.alpha = 0;
package3Btn.alpha = 0;
package4Btn.alpha = 0;
package5Btn.alpha = 0;
package6Btn.alpha = 0;
package7Btn.alpha = 0;
package1Bg.alpha = 0;
package2Bg.alpha = 0;
package3Bg.alpha = 0;
package4Bg.alpha = 0;
package5Bg.alpha = 0;
package6Bg.alpha = 0;
package7Bg.alpha = 0;
// Disable package button interactions
package1Btn.interactive = false;
package2Btn.interactive = false;
package3Btn.interactive = false;
package4Btn.interactive = false;
package5Btn.interactive = false;
package6Btn.interactive = false;
package7Btn.interactive = false;
}
function showDifficultySelection() {
gameMode = 'difficulty';
// Hide main menu
menuTitle.alpha = 0;
vsAIBtn.alpha = 0;
twoPlayerBtn.alpha = 0;
// Disable main menu interactions
vsAIBtn.interactive = false;
twoPlayerBtn.interactive = false;
// Hide settings button in difficulty selection
settingsBtn.alpha = 0;
settingsBtn.interactive = false;
// Show difficulty selection
difficultyTitle.alpha = 1;
easyBtn.alpha = 1;
normalBtn.alpha = 1;
hardBtn.alpha = 1;
backBtn.alpha = 1;
// Enable difficulty button interactions
easyBtn.interactive = true;
normalBtn.interactive = true;
hardBtn.interactive = true;
backBtn.interactive = true;
// Show and animate blocks
easyBlock.alpha = 0.3;
normalBlock.alpha = 0.3;
hardBlock.alpha = 0.3;
animateDifficultyBlocks();
}
function startGame(mode) {
gameMode = mode;
isAIMode = mode === 'ai';
gameBoard.alpha = 1;
settingsBtn.alpha = 0;
settingsBtn.interactive = false;
menuTitle.alpha = 0;
vsAIBtn.alpha = 0;
twoPlayerBtn.alpha = 0;
// Disable menu interactions
vsAIBtn.interactive = false;
twoPlayerBtn.interactive = false;
// Hide difficulty selection
difficultyTitle.alpha = 0;
easyBtn.alpha = 0;
normalBtn.alpha = 0;
hardBtn.alpha = 0;
// Disable difficulty button interactions
easyBtn.interactive = false;
normalBtn.interactive = false;
hardBtn.interactive = false;
// Hide blocks
easyBlock.alpha = 0;
normalBlock.alpha = 0;
hardBlock.alpha = 0;
// Hide confirmation dialog
confirmationBg.alpha = 0;
confirmationText.alpha = 0;
yesBtn.alpha = 0;
noBtn.alpha = 0;
// Disable confirmation dialog interactions
yesBtn.interactive = false;
noBtn.interactive = false;
// Hide back button in all game modes once game starts
backBtn.alpha = 0;
backBtn.interactive = false;
exitBtn.alpha = 1;
// Enable exit button interaction
exitBtn.interactive = true;
// In AI mode, player (1) always starts first
if (isAIMode) {
currentPlayer = 1;
} else {
// In two player mode, random start
currentPlayer = Math.random() < 0.5 ? 1 : 2;
}
updateTurnDisplay();
// Hide settings and package elements
changeAppearanceBtn.alpha = 0;
changeAppearanceBtn.interactive = false;
// Hide current style text
currentStyleText.alpha = 0;
packageTitle.alpha = 0;
package1Btn.alpha = 0;
package2Btn.alpha = 0;
package3Btn.alpha = 0;
package4Btn.alpha = 0;
package5Btn.alpha = 0;
package6Btn.alpha = 0;
package7Btn.alpha = 0;
package1Bg.alpha = 0;
package2Bg.alpha = 0;
package3Bg.alpha = 0;
package4Bg.alpha = 0;
package5Bg.alpha = 0;
package6Bg.alpha = 0;
package7Bg.alpha = 0;
// Disable package button interactions
package1Btn.interactive = false;
package2Btn.interactive = false;
package3Btn.interactive = false;
package4Btn.interactive = false;
package5Btn.interactive = false;
package6Btn.interactive = false;
package7Btn.interactive = false;
// Show statistics during gameplay
statsContainer.alpha = 1;
}
function checkWin() {
var winner = 0;
var winPositions = [];
// Check rows
for (var row = 0; row < 3; row++) {
if (grid[row][0].value !== 0 && grid[row][0].value === grid[row][1].value && grid[row][1].value === grid[row][2].value) {
winner = grid[row][0].value;
winPositions = [{
row: row,
col: 0
}, {
row: row,
col: 1
}, {
row: row,
col: 2
}];
break;
}
}
// Check columns
if (winner === 0) {
for (var col = 0; col < 3; col++) {
if (grid[0][col].value !== 0 && grid[0][col].value === grid[1][col].value && grid[1][col].value === grid[2][col].value) {
winner = grid[0][col].value;
winPositions = [{
row: 0,
col: col
}, {
row: 1,
col: col
}, {
row: 2,
col: col
}];
break;
}
}
}
// Check diagonals
if (winner === 0) {
if (grid[0][0].value !== 0 && grid[0][0].value === grid[1][1].value && grid[1][1].value === grid[2][2].value) {
winner = grid[0][0].value;
winPositions = [{
row: 0,
col: 0
}, {
row: 1,
col: 1
}, {
row: 2,
col: 2
}];
} else if (grid[0][2].value !== 0 && grid[0][2].value === grid[1][1].value && grid[1][1].value === grid[2][0].value) {
winner = grid[0][2].value;
winPositions = [{
row: 0,
col: 2
}, {
row: 1,
col: 1
}, {
row: 2,
col: 0
}];
}
}
if (winner !== 0) {
gameOver = true;
showWinner(winner, winPositions);
return;
}
// Check for draw
var isDraw = true;
for (var r = 0; r < 3; r++) {
for (var c = 0; c < 3; c++) {
if (grid[r][c].value === 0) {
isDraw = false;
break;
}
}
if (!isDraw) break;
}
if (isDraw) {
gameOver = true;
showDraw();
}
}
function showWinner(winner, positions) {
LK.getSound('win').play();
// Update statistics
if (winner === 1) {
gameStats.blueWins++;
storage.blueWins = gameStats.blueWins;
} else {
gameStats.redWins++;
storage.redWins = gameStats.redWins;
}
// Update statistics display
blueStatsText.setText(languageTexts[currentLanguage].blueWins + gameStats.blueWins);
redStatsText.setText(languageTexts[currentLanguage].redWins + gameStats.redWins);
// Custom winner messages based on appearance style
var winnerText = '';
if (currentAppearanceStyle === 0) {
// Klasik X-O
winnerText = winner === 1 ? languageTexts[currentLanguage].blueWin : languageTexts[currentLanguage].redWin;
} else if (currentAppearanceStyle === 1) {
// Tom ve Jerry
if (currentLanguage === 'tr') {
winnerText = winner === 1 ? 'TOM KAZANDI!' : 'JERRY KAZANDI!';
} else {
winnerText = winner === 1 ? 'TOM WON!' : 'JERRY WON!';
}
} else if (currentAppearanceStyle === 2) {
// Batman vs Joker
if (currentLanguage === 'tr') {
winnerText = winner === 1 ? 'BATMAN KAZANDI!' : 'JOKER KAZANDI!';
} else {
winnerText = winner === 1 ? 'BATMAN WON!' : 'JOKER WON!';
}
} else if (currentAppearanceStyle === 3) {
// Ronaldo vs. Messi
if (currentLanguage === 'tr') {
winnerText = winner === 1 ? 'RONALDO KAZANDI!' : 'MESSI KAZANDI!';
} else {
winnerText = winner === 1 ? 'RONALDO WON!' : 'MESSI WON!';
}
} else if (currentAppearanceStyle === 4) {
// Spiderman vs Venom
if (currentLanguage === 'tr') {
winnerText = winner === 1 ? 'SPIDERMAN KAZANDI!' : 'VENOM KAZANDI!';
} else {
winnerText = winner === 1 ? 'SPIDERMAN WON!' : 'VENOM WON!';
}
} else if (currentAppearanceStyle === 5) {
// Steve vs Alex
if (currentLanguage === 'tr') {
winnerText = winner === 1 ? 'STEVE KAZANDI!' : 'ALEX KAZANDI!';
} else {
winnerText = winner === 1 ? 'STEVE WON!' : 'ALEX WON!';
}
} else if (currentAppearanceStyle === 6) {
// Steve vs Alex
if (currentLanguage === 'tr') {
winnerText = winner === 1 ? 'STEVE KAZANDI!' : 'ALEX KAZANDI!';
} else {
winnerText = winner === 1 ? 'STEVE WON!' : 'ALEX WON!';
}
}
var winnerColor = 0x000000; // Black color
statusText.setText(winnerText);
statusText.fill = winnerColor;
statusText.alpha = 1;
blueTurnText.alpha = 0;
redTurnText.alpha = 0;
// Show win line
winLine = gameBoard.addChild(new WinLine());
var startPos = grid[positions[0].row][positions[0].col];
var endPos = grid[positions[2].row][positions[2].col];
var lineColor = winner === 1 ? 0x00aaff : 0xff4444;
winLine.showWinLine(startPos.x, startPos.y, endPos.x, endPos.y, lineColor);
// Show play again button with background
playAgainBtn.interactive = true;
tween(playAgainBg, {
alpha: 0.9
}, {
duration: 500
});
tween(playAgainBtn, {
alpha: 1
}, {
duration: 500
});
// Add pulsing animation to make it more prominent
tween(playAgainBg, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 800,
easing: tween.easeInOut,
repeat: -1,
yoyo: true
});
}
function showDraw() {
// Update statistics
gameStats.draws++;
storage.draws = gameStats.draws;
// Update statistics display
drawStatsText.setText(languageTexts[currentLanguage].draws + gameStats.draws);
statusText.setText(languageTexts[currentLanguage].draw);
statusText.fill = 0x000000; // Black color
statusText.alpha = 1;
blueTurnText.alpha = 0;
redTurnText.alpha = 0;
// Show play again button with background
playAgainBtn.interactive = true;
tween(playAgainBg, {
alpha: 0.9
}, {
duration: 500
});
tween(playAgainBtn, {
alpha: 1
}, {
duration: 500
});
// Add pulsing animation to make it more prominent
tween(playAgainBg, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 800,
easing: tween.easeInOut,
repeat: -1,
yoyo: true
});
}
function makeAIMove() {
if (gameOver || currentPlayer !== 2) return;
// Extra validation for game state
if (!isAIMode || gameMode !== 'ai') return;
// Don't proceed if AI is already processing
if (aiProcessing) return;
// Set AI processing flag to prevent consecutive moves
aiProcessing = true;
// Add safety timeout to clear flag in case of errors
var safetyTimeout = LK.setTimeout(function () {
if (aiProcessing) {
console.log("AI safety timeout triggered - clearing processing flag");
aiProcessing = false; // Safety clear after 5 seconds
}
}, 5000);
// Variable thinking time based on difficulty
var minTime, maxTime;
if (aiDifficulty === 'easy') {
minTime = 300;
maxTime = 800;
} else if (aiDifficulty === 'normal') {
minTime = 500;
maxTime = 1200;
} else {
// hard
minTime = 800;
maxTime = 2000;
}
var thinkingTime = minTime + Math.floor(Math.random() * (maxTime - minTime));
// Use setTimeout to yield frame and prevent blocking
LK.setTimeout(function () {
// Clear the safety timeout since we're now processing
if (safetyTimeout) {
LK.clearTimeout(safetyTimeout);
safetyTimeout = null;
}
// Recheck game state after timeout - ensure AI flag is always cleared
if (gameOver || currentPlayer !== 2 || !isAIMode || gameMode !== 'ai') {
aiProcessing = false;
return;
}
// Additional validation to prevent AI moves during player turn
if (isAIMode && currentPlayer === 1) {
aiProcessing = false;
return;
}
// Extra safety check - if game state is invalid, clear flag
if (!isAIMode || gameMode !== 'ai') {
aiProcessing = false;
return;
}
// Find best move using difficulty-specific strategy
var bestMove = findBestMove();
var moveSuccess = false;
// Validate that we have a valid move and it's still empty
if (bestMove && bestMove.value === 0) {
// Validate coordinates are within bounds
if (bestMove.row >= 0 && bestMove.row < 3 && bestMove.col >= 0 && bestMove.col < 3) {
// Double check the cell is still valid before AI places marker
var targetCell = grid[bestMove.row][bestMove.col];
if (targetCell && targetCell.value === 0 && !gameOver && currentPlayer === 2 && !targetCell.marker) {
if (targetCell.placeMarker(2, function () {
// This callback runs after the AI marker animation completes
checkWin();
if (!gameOver) {
currentPlayer = 1;
updateTurnDisplay();
}
// Clear AI processing flag after move is complete
aiProcessing = false;
})) {
moveSuccess = true;
}
}
}
}
// If the best move failed for any reason, find any empty cell as fallback
if (!moveSuccess && !gameOver && currentPlayer === 2) {
var emptyCells = [];
for (var row = 0; row < 3; row++) {
for (var col = 0; col < 3; col++) {
if (grid[row][col].value === 0 && !grid[row][col].marker) {
emptyCells.push(grid[row][col]);
}
}
}
// Try to place marker on any empty cell
if (emptyCells.length > 0) {
var fallbackCell = emptyCells[Math.floor(Math.random() * emptyCells.length)];
if (fallbackCell.placeMarker(2, function () {
// This callback runs after the fallback AI marker animation completes
checkWin();
if (!gameOver) {
currentPlayer = 1;
updateTurnDisplay();
}
// Clear AI processing flag after move is complete
aiProcessing = false;
})) {
moveSuccess = true;
}
}
}
// If no move was made, clear the processing flag
if (!moveSuccess) {
aiProcessing = false;
}
}, thinkingTime);
}
function findBestMove() {
var emptyCells = [];
var winningMoves = [];
var blockingMoves = [];
var forkMoves = [];
var blockForkMoves = [];
var cornerCells = [];
var edgeCells = [];
var validCells = [];
// Collect all valid empty cells
for (var row = 0; row < 3; row++) {
for (var col = 0; col < 3; col++) {
var cell = grid[row][col];
if (cell && cell.value === 0) {
emptyCells.push(cell);
validCells.push(cell);
// Categorize cell positions
if ((row === 0 || row === 2) && (col === 0 || col === 2)) {
cornerCells.push(cell);
} else if (row === 1 && col === 1) {
// Center cell - handled separately
} else {
edgeCells.push(cell);
}
}
}
}
// Early exit if no valid moves
if (validCells.length === 0) {
return null;
}
// Ensure we always have at least one valid cell to return
if (emptyCells.length === 0) {
return null;
}
// Easy mode: Make deliberate mistakes and play suboptimally
if (aiDifficulty === 'easy') {
// 70% chance to make a completely random move
if (Math.random() < 0.7) {
return validCells[Math.floor(Math.random() * validCells.length)];
}
// 20% chance to avoid winning moves (make mistakes)
if (Math.random() < 0.2) {
var nonWinningMoves = [];
for (var i = 0; i < emptyCells.length; i++) {
var cell = emptyCells[i];
cell.value = 2;
if (!checkWinCondition(2)) {
nonWinningMoves.push(cell);
}
cell.value = 0;
}
if (nonWinningMoves.length > 0) {
return nonWinningMoves[Math.floor(Math.random() * nonWinningMoves.length)];
}
}
// 10% chance to miss blocking player wins
if (Math.random() < 0.1) {
var nonBlockingMoves = [];
for (var i = 0; i < emptyCells.length; i++) {
var cell = emptyCells[i];
cell.value = 1;
if (!checkWinCondition(1)) {
nonBlockingMoves.push(cell);
}
cell.value = 0;
}
if (nonBlockingMoves.length > 0) {
return nonBlockingMoves[Math.floor(Math.random() * nonBlockingMoves.length)];
}
}
// Default: play randomly from all valid moves
return validCells[Math.floor(Math.random() * validCells.length)];
}
// Normal mode: Balanced play with occasional mistakes
if (aiDifficulty === 'normal') {
// Priority 1: Check if AI can win immediately
for (var i = 0; i < emptyCells.length; i++) {
var cell = emptyCells[i];
cell.value = 2;
if (checkWinCondition(2)) {
cell.value = 0;
return cell;
}
cell.value = 0;
}
// Priority 2: Block player from winning
for (var i = 0; i < emptyCells.length; i++) {
var cell = emptyCells[i];
cell.value = 1;
if (checkWinCondition(1)) {
cell.value = 0;
if (Math.random() > 0.02) {
return cell;
}
}
cell.value = 0;
}
// Priority 3: Create forks
if (Math.random() < 0.85) {
forkMoves = checkForFork(2);
if (forkMoves.length > 0) {
return forkMoves[0];
}
}
// Priority 4: Block player forks
if (Math.random() < 0.8) {
var playerForkMoves = checkForFork(1);
if (playerForkMoves.length > 0) {
if (playerForkMoves.length === 1) {
return playerForkMoves[0];
} else {
for (var i = 0; i < emptyCells.length; i++) {
var cell = emptyCells[i];
cell.value = 2;
var createsThreats = false;
for (var j = 0; j < emptyCells.length; j++) {
if (i !== j) {
var testCell = emptyCells[j];
testCell.value = 2;
if (checkWinCondition(2)) {
createsThreats = true;
}
testCell.value = 0;
}
}
cell.value = 0;
if (createsThreats) {
return cell;
}
}
return playerForkMoves[0];
}
}
}
// Priority 5: Basic strategy
if (Math.random() < 0.7) {
var strategicMoves = [];
if (grid[1][1].value === 0) {
strategicMoves.push(grid[1][1]);
strategicMoves.push(grid[1][1]);
}
for (var i = 0; i < cornerCells.length; i++) {
strategicMoves.push(cornerCells[i]);
}
if (strategicMoves.length > 0) {
return strategicMoves[Math.floor(Math.random() * strategicMoves.length)];
}
}
if (emptyCells.length > 0) {
return emptyCells[Math.floor(Math.random() * emptyCells.length)];
}
}
// Advanced position evaluation for hard mode AI
function evaluateHardModePosition(cell) {
var score = 0;
var row = cell.row;
var col = cell.col;
// Base positional values with strategic weighting
if (row === 1 && col === 1) {
score += 15; // Center dominance
} else if ((row === 0 || row === 2) && (col === 0 || col === 2)) {
score += 12; // Corner control
} else {
score += 8; // Edge positions
}
// Evaluate line potential (how many lines this position affects)
var linesControlled = 0;
var lineValues = 0;
// Check row control
var rowEmpty = 0,
rowAI = 0,
rowPlayer = 0;
for (var c = 0; c < 3; c++) {
if (grid[row][c].value === 0) rowEmpty++;else if (grid[row][c].value === 2) rowAI++;else rowPlayer++;
}
if (rowPlayer === 0) {
linesControlled++;
lineValues += rowAI * 3 + rowEmpty;
}
// Check column control
var colEmpty = 0,
colAI = 0,
colPlayer = 0;
for (var r = 0; r < 3; r++) {
if (grid[r][col].value === 0) colEmpty++;else if (grid[r][col].value === 2) colAI++;else colPlayer++;
}
if (colPlayer === 0) {
linesControlled++;
lineValues += colAI * 3 + colEmpty;
}
// Check main diagonal
if (row === col) {
var diagEmpty = 0,
diagAI = 0,
diagPlayer = 0;
for (var i = 0; i < 3; i++) {
if (grid[i][i].value === 0) diagEmpty++;else if (grid[i][i].value === 2) diagAI++;else diagPlayer++;
}
if (diagPlayer === 0) {
linesControlled++;
lineValues += diagAI * 3 + diagEmpty;
}
}
// Check anti-diagonal
if (row + col === 2) {
var antiDiagEmpty = 0,
antiDiagAI = 0,
antiDiagPlayer = 0;
for (var i = 0; i < 3; i++) {
if (grid[i][2 - i].value === 0) antiDiagEmpty++;else if (grid[i][2 - i].value === 2) antiDiagAI++;else antiDiagPlayer++;
}
if (antiDiagPlayer === 0) {
linesControlled++;
lineValues += antiDiagAI * 3 + antiDiagEmpty;
}
}
score += linesControlled * 6 + lineValues * 2;
// Strategic pattern bonuses
// Opposite corner control
if (row === 0 && col === 0 && grid[2][2].value === 2 || row === 2 && col === 2 && grid[0][0].value === 2 || row === 0 && col === 2 && grid[2][0].value === 2 || row === 2 && col === 0 && grid[0][2].value === 2) {
score += 8; // Diagonal dominance
}
// Adjacent to AI pieces (connection bonus)
var adjacentAI = 0;
var checkAdj = [{
r: row - 1,
c: col
}, {
r: row + 1,
c: col
}, {
r: row,
c: col - 1
}, {
r: row,
c: col + 1
}];
for (var i = 0; i < checkAdj.length; i++) {
var adj = checkAdj[i];
if (adj.r >= 0 && adj.r < 3 && adj.c >= 0 && adj.c < 3) {
if (grid[adj.r][adj.c].value === 2) adjacentAI++;
}
}
score += adjacentAI * 4;
return score;
}
// Check for forks (moves that create two winning threats)
function checkForFork(player) {
var forkCells = [];
for (var i = 0; i < emptyCells.length; i++) {
var cell = emptyCells[i];
cell.value = player;
var winningLineCount = 0;
// Count how many winning moves this creates
for (var j = 0; j < emptyCells.length; j++) {
if (i !== j) {
var testCell = emptyCells[j];
testCell.value = player;
if (checkWinCondition(player)) {
winningLineCount++;
}
testCell.value = 0;
}
}
cell.value = 0;
if (winningLineCount >= 2) {
forkCells.push(cell);
}
}
return forkCells;
}
// Adjust strategy based on difficulty
var randomnessFactor = Math.random();
// Difficulty-based mistake chances
var strategyQuality;
if (aiDifficulty === 'easy') {
strategyQuality = 0; // No strategic moves
} else if (aiDifficulty === 'normal') {
strategyQuality = 0.6; // Medium quality strategic moves
} else {
// hard - Perfect play with zero mistakes
strategyQuality = 1.0; // Perfect strategic moves
}
// Hard mode AI - Perfect play with advanced strategy evaluation
if (aiDifficulty === 'hard') {
// Priority 1: ALWAYS win if possible (0% miss rate)
for (var i = 0; i < emptyCells.length; i++) {
var cell = emptyCells[i];
cell.value = 2;
if (checkWinCondition(2)) {
cell.value = 0;
return cell; // IMMEDIATELY take winning move - no randomness
}
cell.value = 0;
}
// Priority 2: ALWAYS block player wins (0% miss rate)
for (var i = 0; i < emptyCells.length; i++) {
var cell = emptyCells[i];
cell.value = 1;
if (checkWinCondition(1)) {
cell.value = 0;
return cell; // IMMEDIATELY block - no randomness
}
cell.value = 0;
}
// Priority 3: Create forks (multiple winning threats)
forkMoves = checkForFork(2);
if (forkMoves.length > 0) {
return forkMoves[0]; // Take any fork opportunity
}
// Priority 4: Block player forks with counter-strategy
var playerForkMoves = checkForFork(1);
if (playerForkMoves.length > 0) {
// If player can create multiple forks, create a counter-threat
if (playerForkMoves.length > 1) {
// Look for moves that force player to defend while blocking fork
for (var i = 0; i < emptyCells.length; i++) {
var cell = emptyCells[i];
cell.value = 2;
var threatsCreated = 0;
for (var j = 0; j < emptyCells.length; j++) {
if (i !== j) {
var testCell = emptyCells[j];
testCell.value = 2;
if (checkWinCondition(2)) {
threatsCreated++;
}
testCell.value = 0;
}
}
cell.value = 0;
if (threatsCreated > 0) {
return cell; // Counter-threat to force defense
}
}
}
// Otherwise block the fork
return playerForkMoves[0];
}
// Priority 5: Optimal opening strategy
if (emptyCells.length === 9) {
// First move: always take center or corner
if (grid[1][1].value === 0) {
return grid[1][1]; // Center is strongest opening
} else {
return cornerCells[0]; // Fallback to corner
}
}
if (emptyCells.length === 8) {
// Second move response
if (grid[1][1].value === 1) {
// Player took center, take any corner
return cornerCells[0];
} else {
// Player took corner or edge, take center
if (grid[1][1].value === 0) {
return grid[1][1];
}
}
}
// Priority 6: Advanced positional strategy with minimax evaluation
var bestMove = null;
var bestScore = -1000;
for (var i = 0; i < emptyCells.length; i++) {
var cell = emptyCells[i];
var score = evaluateHardModePosition(cell);
// Add advanced tactical bonuses
if (cell.row === 1 && cell.col === 1) score += 15; // Center control
if ((cell.row === 0 || cell.row === 2) && (cell.col === 0 || cell.col === 2)) score += 12; // Corner control
// Evaluate future position strength
cell.value = 2;
var futureThreats = 0;
for (var j = 0; j < emptyCells.length; j++) {
if (i !== j) {
var testCell = emptyCells[j];
testCell.value = 2;
if (checkWinCondition(2)) futureThreats++;
testCell.value = 0;
}
}
score += futureThreats * 8; // Bonus for creating future threats
cell.value = 0;
if (score > bestScore) {
bestScore = score;
bestMove = cell;
}
}
if (bestMove) {
return bestMove;
}
}
// Priority 5: Advanced tactical personalities
var moveChoices = [];
var moveScores = [];
if (aiPersonality === 0) {
// Perfect player - uses optimal strategy
if (emptyCells.length === 9) {
// First move: prefer corner
moveChoices = cornerCells.slice();
} else if (emptyCells.length === 8) {
// Second move response
if (grid[1][1].value === 1) {
// Player took center, take corner
moveChoices = cornerCells.slice();
} else {
// Player took corner or edge, take center
if (grid[1][1].value === 0) {
moveChoices.push(grid[1][1]);
}
}
} else {
// Evaluate all positions
for (var i = 0; i < emptyCells.length; i++) {
var score = evaluatePosition(emptyCells[i]);
moveScores.push({
cell: emptyCells[i],
score: score
});
}
moveScores.sort(function (a, b) {
return b.score - a.score;
});
// Take top scoring moves
var topScore = moveScores[0].score;
for (var i = 0; i < moveScores.length; i++) {
if (moveScores[i].score >= topScore - 1) {
moveChoices.push(moveScores[i].cell);
}
}
}
} else if (aiPersonality === 1) {
// Trap setter - tries to create winning patterns
if (grid[1][1].value === 0) {
moveChoices.push(grid[1][1]);
moveChoices.push(grid[1][1]); // Double weight
}
// Look for L-shaped patterns
if (grid[0][0].value === 2 && grid[2][2].value === 0) {
moveChoices.push(grid[2][2]);
}
if (grid[0][2].value === 2 && grid[2][0].value === 0) {
moveChoices.push(grid[2][0]);
}
// Add corners for trap potential
if (cornerCells.length > 0) {
moveChoices = moveChoices.concat(cornerCells);
}
} else if (aiPersonality === 2) {
// Defensive player - blocks and controls center
if (grid[1][1].value === 0) {
moveChoices.push(grid[1][1]);
moveChoices.push(grid[1][1]);
moveChoices.push(grid[1][1]); // Triple weight for center
}
// Prefer moves that block multiple lines
for (var i = 0; i < emptyCells.length; i++) {
var blockCount = countWinningLines(emptyCells[i].row, emptyCells[i].col, 1);
if (blockCount >= 2) {
moveChoices.push(emptyCells[i]);
}
}
if (moveChoices.length === 0 && cornerCells.length > 0) {
moveChoices = cornerCells.slice();
}
} else if (aiPersonality === 3) {
// Mirror player - plays symmetrically
var playerMoves = [];
for (var r = 0; r < 3; r++) {
for (var c = 0; c < 3; c++) {
if (grid[r][c].value === 1) {
playerMoves.push({
row: r,
col: c
});
}
}
}
if (playerMoves.length > 0) {
var lastMove = playerMoves[playerMoves.length - 1];
// Try to mirror across center
var mirrorRow = 2 - lastMove.row;
var mirrorCol = 2 - lastMove.col;
if (grid[mirrorRow][mirrorCol].value === 0) {
moveChoices.push(grid[mirrorRow][mirrorCol]);
moveChoices.push(grid[mirrorRow][mirrorCol]); // Double weight
}
}
// Add strategic positions
if (grid[1][1].value === 0) {
moveChoices.push(grid[1][1]);
}
if (cornerCells.length > 0) {
moveChoices.push(cornerCells[Math.floor(Math.random() * cornerCells.length)]);
}
} else if (aiPersonality === 4) {
// Edge control player - unusual but effective
if (edgeCells.length > 0) {
// Prefer edges that connect to existing pieces
for (var i = 0; i < edgeCells.length; i++) {
var edge = edgeCells[i];
var adjacentAI = 0;
// Check adjacent cells
var checkPositions = [{
r: edge.row - 1,
c: edge.col
}, {
r: edge.row + 1,
c: edge.col
}, {
r: edge.row,
c: edge.col - 1
}, {
r: edge.row,
c: edge.col + 1
}];
for (var j = 0; j < checkPositions.length; j++) {
var pos = checkPositions[j];
if (pos.r >= 0 && pos.r < 3 && pos.c >= 0 && pos.c < 3) {
if (grid[pos.r][pos.c].value === 2) {
adjacentAI++;
}
}
}
if (adjacentAI > 0) {
moveChoices.push(edge);
moveChoices.push(edge); // Double weight for connected edges
}
}
if (moveChoices.length === 0) {
moveChoices = edgeCells.slice();
}
}
// Sometimes take center
if (Math.random() < 0.3 && grid[1][1].value === 0) {
moveChoices.push(grid[1][1]);
}
} else if (aiPersonality === 5) {
// Chaos player - creates complex board states
var complexityScore = [];
for (var i = 0; i < emptyCells.length; i++) {
var cell = emptyCells[i];
// Calculate how many lines this move affects
var linesAffected = 0;
if (true) linesAffected++; // Row
if (true) linesAffected++; // Column
if (cell.row === cell.col || cell.row + cell.col === 2) {
linesAffected++; // Diagonal
}
complexityScore.push({
cell: cell,
complexity: linesAffected
});
}
// Prefer high complexity moves
complexityScore.sort(function (a, b) {
return b.complexity - a.complexity;
});
for (var i = 0; i < Math.min(3, complexityScore.length); i++) {
moveChoices.push(complexityScore[i].cell);
}
} else if (aiPersonality === 6) {
// Pattern player - follows specific winning patterns
var patterns = [
// Corner-opposite-corner
[{
r: 0,
c: 0
}, {
r: 2,
c: 2
}], [{
r: 0,
c: 2
}, {
r: 2,
c: 0
}],
// L-shapes
[{
r: 0,
c: 0
}, {
r: 0,
c: 2
}], [{
r: 0,
c: 0
}, {
r: 2,
c: 0
}], [{
r: 2,
c: 2
}, {
r: 2,
c: 0
}], [{
r: 2,
c: 2
}, {
r: 0,
c: 2
}]];
for (var p = 0; p < patterns.length; p++) {
var pattern = patterns[p];
var hasFirst = grid[pattern[0].r][pattern[0].c].value === 2;
var secondEmpty = grid[pattern[1].r][pattern[1].c].value === 0;
if (hasFirst && secondEmpty) {
moveChoices.push(grid[pattern[1].r][pattern[1].c]);
moveChoices.push(grid[pattern[1].r][pattern[1].c]); // Double weight
}
}
// Default to smart positions
if (moveChoices.length === 0) {
if (grid[1][1].value === 0) {
moveChoices.push(grid[1][1]);
}
if (cornerCells.length > 0) {
moveChoices = moveChoices.concat(cornerCells);
}
}
} else {
// Adaptive player - changes strategy based on game state
var gamePhase = 9 - emptyCells.length; // 0-8, higher = later
if (gamePhase <= 2) {
// Early game: control key positions
if (grid[1][1].value === 0) {
moveChoices.push(grid[1][1]);
moveChoices.push(grid[1][1]);
}
if (cornerCells.length > 0) {
moveChoices = moveChoices.concat(cornerCells);
}
} else if (gamePhase <= 5) {
// Mid game: create threats
for (var i = 0; i < emptyCells.length; i++) {
var threatLevel = countWinningLines(emptyCells[i].row, emptyCells[i].col, 2);
if (threatLevel >= 1) {
moveChoices.push(emptyCells[i]);
if (threatLevel >= 2) {
moveChoices.push(emptyCells[i]); // Extra weight for multi-threats
}
}
}
} else {
// Late game: optimize winning chances
for (var i = 0; i < emptyCells.length; i++) {
moveChoices.push(emptyCells[i]);
}
}
}
// Add calculated randomness
if (Math.random() < 0.1) {
// 10% chance to add unexpected move
if (validCells.length > 0) {
var randomCell = validCells[Math.floor(Math.random() * validCells.length)];
moveChoices.push(randomCell);
}
}
// If we have strategic choices, pick from them
if (moveChoices.length > 0) {
// Sometimes pick the most frequent choice (if duplicates exist)
var choiceFrequency = {};
for (var i = 0; i < moveChoices.length; i++) {
var key = moveChoices[i].row + ',' + moveChoices[i].col;
choiceFrequency[key] = (choiceFrequency[key] || 0) + 1;
}
// Create weighted selection
var weightedChoices = [];
for (var i = 0; i < moveChoices.length; i++) {
weightedChoices.push(moveChoices[i]);
}
return weightedChoices[Math.floor(Math.random() * weightedChoices.length)];
}
// Easy mode already handled above with helpful logic
// Final fallback: intelligent selection
var fallbackChoices = [];
// Prioritize based on position value (less strategic in easy mode)
if (aiDifficulty !== 'easy' || Math.random() < 0.5) {
if (grid[1][1].value === 0) {
fallbackChoices.push(grid[1][1]);
}
}
if (cornerCells.length > 0 && (aiDifficulty !== 'easy' || Math.random() < 0.6)) {
fallbackChoices = fallbackChoices.concat(cornerCells);
}
if (edgeCells.length > 0 && (aiDifficulty === 'easy' || Math.random() < 0.3)) {
fallbackChoices.push(edgeCells[Math.floor(Math.random() * edgeCells.length)]);
}
if (fallbackChoices.length === 0) {
fallbackChoices = validCells;
}
if (fallbackChoices.length > 0) {
return fallbackChoices[Math.floor(Math.random() * fallbackChoices.length)];
}
// Ultimate fallback: return first empty cell found
for (var row = 0; row < 3; row++) {
for (var col = 0; col < 3; col++) {
if (grid[row][col].value === 0 && !grid[row][col].marker) {
return grid[row][col];
}
}
}
// If still no valid move found, return any empty cell regardless of marker status
for (var row = 0; row < 3; row++) {
for (var col = 0; col < 3; col++) {
if (grid[row][col].value === 0) {
return grid[row][col];
}
}
}
return null;
}
function checkWinCondition(player) {
// Check rows
for (var row = 0; row < 3; row++) {
if (grid[row][0].value === player && grid[row][1].value === player && grid[row][2].value === player) {
return true;
}
}
// Check columns
for (var col = 0; col < 3; col++) {
if (grid[0][col].value === player && grid[1][col].value === player && grid[2][col].value === player) {
return true;
}
}
// Check diagonals
if (grid[0][0].value === player && grid[1][1].value === player && grid[2][2].value === player) {
return true;
}
if (grid[0][2].value === player && grid[1][1].value === player && grid[2][0].value === player) {
return true;
}
return false;
}
function resetGame() {
gameOver = false;
// Immediately clear AI processing to prevent stuck states
aiProcessing = false;
// Clear any pending AI timeouts
LK.clearTimeout(); // Clear any pending timeouts
// Stop all active tweens to prevent conflicts
// Stop tweens on UI elements
tween.stop(playAgainBg);
tween.stop(playAgainBtn);
tween.stop(statusText);
// Stop tweens on difficulty blocks
tween.stop(easyBlock);
tween.stop(normalBlock);
tween.stop(hardBlock);
// Stop tweens on confirmation dialog elements
tween.stop(confirmationBg);
tween.stop(confirmationText);
tween.stop(yesBtn);
tween.stop(noBtn);
// Stop tweens on all cell markers
for (var row = 0; row < 3; row++) {
for (var col = 0; col < 3; col++) {
var cell = grid[row][col];
if (cell.marker) {
tween.stop(cell.marker);
}
}
}
// Force clear any stuck AI state
if (isAIMode && currentPlayer === 2) {
currentPlayer = 1; // Reset to player's turn
}
// Start according to game mode
if (gameMode === 'ai') {
currentPlayer = 1; // Player always starts in AI mode
isAIMode = true;
} else if (gameMode === 'twoPlayer') {
currentPlayer = Math.random() < 0.5 ? 1 : 2;
isAIMode = false;
} else {
// Menu mode
currentPlayer = 1;
isAIMode = false;
}
// Clear grid
for (var row = 0; row < 3; row++) {
for (var col = 0; col < 3; col++) {
var cell = grid[row][col];
cell.value = 0;
if (cell.marker) {
// Stop any active tweens on marker before destroying
tween.stop(cell.marker);
// Reset marker properties to prevent visual glitches
cell.marker.alpha = 0;
cell.marker.scaleX = 1;
cell.marker.scaleY = 1;
cell.marker.tint = 0xffffff;
cell.marker.rotation = 0;
// Remove from parent before destroying
if (cell.marker.parent) {
cell.marker.parent.removeChild(cell.marker);
}
cell.marker.destroy();
cell.marker = null;
}
// Clean up second marker for Tom ve Jerry style
if (cell.marker2) {
// Stop any active tweens on second marker before destroying
tween.stop(cell.marker2);
// Reset marker properties to prevent visual glitches
cell.marker2.alpha = 0;
cell.marker2.scaleX = 1;
cell.marker2.scaleY = 1;
cell.marker2.tint = 0xffffff;
cell.marker2.rotation = 0;
// Remove from parent before destroying
if (cell.marker2.parent) {
cell.marker2.parent.removeChild(cell.marker2);
}
cell.marker2.destroy();
cell.marker2 = null;
}
}
}
// Clear UI
statusText.setText('');
statusText.alpha = 0;
playAgainBtn.alpha = 0;
playAgainBg.alpha = 0;
// Stop any pulsing animation on play again button
tween.stop(playAgainBg);
tween.stop(playAgainBtn);
playAgainBg.scaleX = 1;
playAgainBg.scaleY = 1;
playAgainBtn.interactive = false;
// Hide all settings and package UI elements
changeAppearanceBtn.alpha = 0;
changeAppearanceBtn.interactive = false;
// Hide current style text
currentStyleText.alpha = 0;
packageTitle.alpha = 0;
package1Btn.alpha = 0;
package2Btn.alpha = 0;
package3Btn.alpha = 0;
package4Btn.alpha = 0;
package5Btn.alpha = 0;
package6Btn.alpha = 0;
package7Btn.alpha = 0;
package1Bg.alpha = 0;
package2Bg.alpha = 0;
package3Bg.alpha = 0;
package4Bg.alpha = 0;
package5Bg.alpha = 0;
package6Bg.alpha = 0;
package7Bg.alpha = 0;
// Disable package button interactions
package1Btn.interactive = false;
package2Btn.interactive = false;
package3Btn.interactive = false;
package4Btn.interactive = false;
package5Btn.interactive = false;
package6Btn.interactive = false;
package7Btn.interactive = false;
// Remove win line
if (winLine) {
// Stop any active tweens on win line to prevent memory leaks
tween.stop(winLine.line);
tween.stop(winLine); // Stop any tweens on the container too
// Reset line properties before destroying
winLine.line.alpha = 0;
winLine.line.scaleX = 0;
winLine.line.tint = 0xffffff; // Reset tint
// Remove from parent before destroying
if (winLine.parent) {
winLine.parent.removeChild(winLine);
}
winLine.destroy();
winLine = null;
}
updateTurnDisplay();
}
// Play again button handler
playAgainBtn.down = function (x, y, obj) {
if (gameOver) {
resetGame();
}
};
// Add small delay to prevent initial freeze when entering game
var gameReady = false;
LK.setTimeout(function () {
gameReady = true;
}, 50); // Reduced delay for better responsiveness /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Cell = Container.expand(function (row, col) {
var self = Container.call(this);
self.row = row;
self.col = col;
self.value = 0; // 0 = empty, 1 = X (blue), 2 = O (red)
var cellBg = self.attachAsset('cell', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.01 // Make almost invisible but still interactive
});
// Make the entire cell area interactive
self.interactive = true;
self.hitArea = new Rectangle(-290, -290, 580, 580);
self.marker = null;
// Add hover effect to show clickable area
self.move = function (x, y, obj) {
if (!gameReady || gameOver || self.value !== 0 || gameMode === 'menu') return;
if (isAIMode && currentPlayer !== 1) return;
cellBg.alpha = 0.2; // Show cell is hoverable
};
// Reset hover effect when mouse leaves
self.up = function (x, y, obj) {
if (self.value === 0) {
cellBg.alpha = 0.01; // Reset to almost invisible
}
};
self.placeMarker = function (type, callback) {
if (self.value !== 0) return false;
// Prevent placing marker if already has one or is animating
if (self.marker || self.value !== 0) return false;
// In AI mode, extra validation
if (isAIMode && type === 1 && aiProcessing) return false;
if (isAIMode && type === 2 && !aiProcessing) return false;
self.value = type;
// Get asset names based on current appearance style
var xAssetName, oAssetName;
if (currentAppearanceStyle === 0) {
xAssetName = 'xMarker';
oAssetName = 'oMarker';
} else if (currentAppearanceStyle === 1) {
xAssetName = 'xMarkerStyle1';
oAssetName = 'oMarkerStyle1';
} else if (currentAppearanceStyle === 2) {
xAssetName = 'xMarkerStyle2';
oAssetName = 'oMarkerStyle2';
} else if (currentAppearanceStyle === 3) {
xAssetName = 'xMarkerStyle3';
oAssetName = 'oMarkerStyle3';
} else if (currentAppearanceStyle === 4) {
xAssetName = 'xMarkerStyle4';
oAssetName = 'oMarkerStyle4';
} else if (currentAppearanceStyle === 5) {
xAssetName = 'xMarkerStyle5';
oAssetName = 'oMarkerStyle5';
} else if (currentAppearanceStyle === 6) {
xAssetName = 'xMarkerStyle6';
oAssetName = 'oMarkerStyle6';
}
if (type === 1) {
// Blue X
if (currentAppearanceStyle === 1) {
// Style 1: Blue square for X
self.marker = self.attachAsset('xMarkerStyle1', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
});
tween(self.marker, {
alpha: 0.9,
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 300,
easing: tween.easeOut,
onFinish: callback
});
} else if (currentAppearanceStyle === 2) {
// Style 2: Purple square for X
self.marker = self.attachAsset('xMarkerStyle2', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
});
tween(self.marker, {
alpha: 0.9,
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 300,
easing: tween.easeOut,
onFinish: callback
});
} else if (currentAppearanceStyle === 3) {
// Style 3: Pink square for X
self.marker = self.attachAsset('xMarkerStyle3', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
});
tween(self.marker, {
alpha: 0.9,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 300,
easing: tween.easeOut,
onFinish: callback
});
} else if (currentAppearanceStyle === 4) {
// Style 4: Ronaldo for X
self.marker = self.attachAsset('xMarkerStyle4', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
});
tween(self.marker, {
alpha: 0.9,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 300,
easing: tween.easeOut,
onFinish: callback
});
} else if (currentAppearanceStyle === 5) {
// Style 5: Spiderman for X
self.marker = self.attachAsset('xMarkerStyle5', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
});
tween(self.marker, {
alpha: 0.9,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 300,
easing: tween.easeOut,
onFinish: callback
});
} else if (currentAppearanceStyle === 6) {
// Style 6: Steve for X
self.marker = self.attachAsset('xMarkerStyle6', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
});
tween(self.marker, {
alpha: 0.9,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 300,
easing: tween.easeOut,
onFinish: callback
});
} else {
// Standard X marker (style 0)
self.marker = self.attachAsset(xAssetName, {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
});
tween(self.marker, {
alpha: 0.9,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 300,
easing: tween.easeOut,
onFinish: callback
});
}
} else {
// Red O
if (currentAppearanceStyle === 1) {
// Style 1: Red square for O
self.marker = self.attachAsset('oMarkerStyle1', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
});
tween(self.marker, {
alpha: 0.9,
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 300,
easing: tween.easeOut,
onFinish: callback
});
} else if (currentAppearanceStyle === 2) {
// Style 2: Orange square for O
self.marker = self.attachAsset('oMarkerStyle2', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
});
tween(self.marker, {
alpha: 0.9,
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 300,
easing: tween.easeOut,
onFinish: callback
});
} else if (currentAppearanceStyle === 3) {
// Style 3: Green square for O
self.marker = self.attachAsset('oMarkerStyle3', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
});
tween(self.marker, {
alpha: 0.9,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 300,
easing: tween.easeOut,
onFinish: callback
});
} else if (currentAppearanceStyle === 4) {
// Style 4: Messi for O
self.marker = self.attachAsset('oMarkerStyle4', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
});
tween(self.marker, {
alpha: 0.9,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 300,
easing: tween.easeOut,
onFinish: callback
});
} else if (currentAppearanceStyle === 5) {
// Style 5: Venom for O
self.marker = self.attachAsset('oMarkerStyle5', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
});
tween(self.marker, {
alpha: 0.9,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 300,
easing: tween.easeOut,
onFinish: callback
});
} else if (currentAppearanceStyle === 6) {
// Style 6: Alex for O
self.marker = self.attachAsset('oMarkerStyle6', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
});
tween(self.marker, {
alpha: 0.9,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 300,
easing: tween.easeOut,
onFinish: callback
});
} else {
// Style 0: use original assets
self.marker = self.attachAsset(oAssetName, {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
});
tween(self.marker, {
alpha: 0.9,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 300,
easing: tween.easeOut,
onFinish: callback
});
}
}
LK.getSound('place').play();
return true;
};
self.down = function (x, y, obj) {
// Basic validation checks
if (!gameReady || gameOver || gameMode === 'menu') return;
if (self.value !== 0) return; // Cell already occupied
// Prevent placing markers when game board is not visible
if (gameBoard.alpha === 0) return;
// In AI mode, prevent ALL player input during AI processing or when it's not player's turn
if (isAIMode && (currentPlayer !== 1 || aiProcessing)) return;
// Additional safety check to prevent race conditions
if (isAIMode && currentPlayer === 2) return;
// Extra validation: ensure no other animations are running
if (isAIMode && aiProcessing) {
console.log("Player input blocked - AI is processing");
return;
}
// Check if any cell is currently animating to prevent interference
for (var r = 0; r < 3; r++) {
for (var c = 0; c < 3; c++) {
var checkCell = grid[r][c];
if (checkCell && checkCell.marker && checkCell.marker.alpha < 0.9 && checkCell.marker.alpha > 0) {
return; // Animation in progress, prevent input
}
}
}
// Place the marker with animation and wait for completion
if (self.placeMarker(currentPlayer, function () {
// This callback runs after the marker animation completes
checkWin();
if (!gameOver) {
if (isAIMode && currentPlayer === 1) {
// AI mode - player played, now AI plays
currentPlayer = 2;
updateTurnDisplay();
// Only start AI processing if not already processing
if (!aiProcessing) {
aiProcessing = true;
LK.setTimeout(function () {
if (!gameOver && currentPlayer === 2 && isAIMode) {
aiProcessing = false;
makeAIMove();
} else {
aiProcessing = false;
}
}, 100); // Small delay to ensure UI updates
}
} else if (isAIMode && currentPlayer === 2) {
// This shouldn't happen in AI mode since AI doesn't click
currentPlayer = 1;
updateTurnDisplay();
} else {
// Two player mode - switch players normally
currentPlayer = currentPlayer === 1 ? 2 : 1;
updateTurnDisplay();
}
}
})) {
// Marker placement started successfully - disable further input until animation completes
}
};
return self;
});
var WinLine = Container.expand(function () {
var self = Container.call(this);
self.line = self.attachAsset('winLine', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0,
scaleX: 0
});
self.showWinLine = function (startX, startY, endX, endY, color) {
var deltaX = endX - startX;
var deltaY = endY - startY;
var angle = Math.atan2(deltaY, deltaX);
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
self.x = startX + deltaX / 2;
self.y = startY + deltaY / 2;
self.line.rotation = angle;
self.line.tint = color;
self.line.width = distance;
tween(self.line, {
alpha: 1,
scaleX: 1
}, {
duration: 500,
easing: tween.easeOut
});
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a1a1a
});
/****
* Game Code
****/
// Alternative appearance styles
var grid = [];
var currentPlayer = 1; // 1 = Blue X, 2 = Red O
var gameOver = false;
var winLine = null;
var gameMode = 'menu'; // 'menu', 'ai', 'twoPlayer', 'difficulty'
var isAIMode = false;
var aiDifficulty = 'normal'; // 'easy', 'normal', 'hard'
var aiProcessing = false; // Flag to prevent AI from interfering with player moves
var currentLanguage = storage.language || 'tr'; // 'tr' for Turkish, 'en' for English
// Initialize appearance style from storage - default to normal X and O style
var currentAppearanceStyle = storage.appearanceStyle !== undefined ? storage.appearanceStyle : 0; // 0-3 for different X/O styles, start with 0 (normal X and O)
// Initialize statistics from storage with defaults
var gameStats = {
blueWins: storage.blueWins || 0,
redWins: storage.redWins || 0,
draws: storage.draws || 0
};
var selectedDifficulty = ''; // Store selected difficulty for confirmation
var isResetConfirmation = false; // Track if we're in reset confirmation mode
var languageTexts = {
tr: {
blueTurn: 'Sıra: Zeus',
redTurn: 'Sıra: HADES',
blueWin: 'ZEUS KAZANDI!',
redWin: 'HADES KAZANDI!',
draw: 'BERABERE!',
playAgain: 'Tekrar Oyna',
language: 'Türkçe',
vsAI: 'Yapay Zeka ile Oyna',
twoPlayer: 'İki Kişilik Oyna',
selectMode: 'Oyun Modunu Seçin',
back: '← Geri',
exit: 'Çıkış',
selectDifficulty: 'Zorluk Seçin',
easy: 'Kolay',
normal: 'Normal',
hard: 'Zor',
confirmEasy: 'Kolay modu seçmek istiyor musunuz?',
confirmNormal: 'Normal modu seçmek istiyor musunuz?',
confirmHard: 'Zor modu seçmek istiyor musunuz?',
yes: 'Evet',
no: 'Hayır',
blueWins: 'ZEUS Galibiyetler: ',
redWins: 'HADES Galibiyetler: ',
draws: 'Beraberlikler: ',
resetStats: 'İstatistikleri Sıfırla',
confirmReset: 'İstatistikleri sıfırlamaktan emin misiniz?',
settings: 'Ayarlar',
changeAppearance: 'Görünümü Değiştir',
selectPackage: 'Paket Seçin',
package1: 'Klasik X-O',
package2: 'Tom ve Jerry',
package3: 'Batman vs Joker',
package4: 'Ronaldo vs. Messi',
package5: 'Spiderman vs Venom',
package6: 'Steve vs Alex',
package7: 'Belirsiz',
selected: 'Seçili: '
},
en: {
blueTurn: 'Turn: Blue',
redTurn: 'Turn: HADES',
blueWin: 'ZEUS WON!',
redWin: 'HADES WON!',
draw: 'DRAW!',
playAgain: 'Play Again',
language: 'English',
vsAI: 'Play vs AI',
twoPlayer: 'Two Player',
selectMode: 'Select Game Mode',
back: '← Back',
exit: 'Exit',
selectDifficulty: 'Select Difficulty',
easy: 'Easy',
normal: 'Normal',
hard: 'Hard',
confirmEasy: 'Do you want to select Easy mode?',
confirmNormal: 'Do you want to select Normal mode?',
confirmHard: 'Do you want to select Hard mode?',
yes: 'Yes',
no: 'No',
blueWins: 'ZEUS Wins: ',
redWins: 'HADES Wins: ',
draws: 'Draws: ',
resetStats: 'Reset Statistics',
confirmReset: 'Are you sure you want to reset statistics?',
settings: 'Settings',
changeAppearance: 'Change Appearance',
selectPackage: 'Select Package',
package1: 'Classic X-O',
package2: 'Tom ve Jerry',
package3: 'Batman vs Joker',
package4: 'Ronaldo vs. Messi',
package5: 'Spiderman vs Venom',
package6: 'Steve vs Alex',
package7: 'Belirsiz',
selected: 'Selected: '
}
};
// Game setup
var gameBoard = game.addChild(new Container());
gameBoard.x = 2048 / 2;
gameBoard.y = 2732 / 2;
gameBoard.scaleX = 1.2;
gameBoard.scaleY = 1.2;
gameBoard.alpha = 0; // Hidden initially
// Create background
var background = gameBoard.attachAsset('gridBackground', {
anchorX: 0.5,
anchorY: 0.5
});
// Create grid lines
var verticalLine1 = gameBoard.attachAsset('gridLine', {
anchorX: 0.5,
anchorY: 0.5,
x: -300,
height: 1800
});
var verticalLine2 = gameBoard.attachAsset('gridLine', {
anchorX: 0.5,
anchorY: 0.5,
x: 300,
height: 1800
});
var horizontalLine1 = gameBoard.attachAsset('gridLine', {
anchorX: 0.5,
anchorY: 0.5,
y: -300,
width: 1800,
height: 8
});
var horizontalLine2 = gameBoard.attachAsset('gridLine', {
anchorX: 0.5,
anchorY: 0.5,
y: 300,
width: 1800,
height: 8
});
// Create cells
for (var row = 0; row < 3; row++) {
grid[row] = [];
for (var col = 0; col < 3; col++) {
var cell = gameBoard.addChild(new Cell(row, col));
cell.x = (col - 1) * 600;
cell.y = (row - 1) * 600;
grid[row][col] = cell;
}
}
// UI Elements
var blueTurnText = new Text2(languageTexts[currentLanguage].blueTurn, {
size: 100,
fill: 0x00AAFF
});
blueTurnText.anchor.set(0.5, 0);
LK.gui.top.addChild(blueTurnText);
blueTurnText.y = 220;
var redTurnText = new Text2(languageTexts[currentLanguage].redTurn, {
size: 100,
fill: 0xff0000
});
redTurnText.anchor.set(0.5, 0);
LK.gui.top.addChild(redTurnText);
redTurnText.y = 220;
var languageBtn = new Text2(languageTexts[currentLanguage === 'tr' ? 'en' : 'tr'].language, {
size: 60,
fill: 0xFFFFFF
});
languageBtn.anchor.set(0.5, 0);
LK.gui.top.addChild(languageBtn);
languageBtn.y = 120;
var statusText = new Text2('', {
size: 100,
fill: 0xFFFFFF
});
statusText.anchor.set(0.5, 0.5);
LK.gui.center.addChild(statusText);
statusText.y = 400;
// Create background for play again button
var playAgainBg = LK.getAsset('cell', {
anchorX: 0.5,
anchorY: 0.5,
width: 500,
height: 120,
tint: 0x4CAF50,
alpha: 0
});
LK.gui.center.addChild(playAgainBg);
playAgainBg.y = 550;
var playAgainBtn = new Text2(languageTexts[currentLanguage].playAgain, {
size: 90,
fill: 0xFFFFFF
});
playAgainBtn.anchor.set(0.5, 0.5);
playAgainBtn.interactive = false;
playAgainBtn.hitArea = new Rectangle(-250, -60, 500, 120);
LK.gui.center.addChild(playAgainBtn);
playAgainBtn.y = 550;
playAgainBtn.alpha = 0;
// Settings button
var settingsBtn = new Text2(languageTexts[currentLanguage].settings, {
size: 80,
fill: 0xFFAA00
});
settingsBtn.anchor.set(0.5, 0.5);
settingsBtn.interactive = false;
settingsBtn.hitArea = new Rectangle(-100, -40, 200, 80);
LK.gui.center.addChild(settingsBtn);
settingsBtn.y = -300;
// Menu UI elements
var menuTitle = new Text2(languageTexts[currentLanguage].selectMode, {
size: 120,
fill: 0xFFFFFF
});
menuTitle.anchor.set(0.5, 0.5);
LK.gui.center.addChild(menuTitle);
menuTitle.y = -200;
// AI Difficulty selection elements
var difficultyTitle = new Text2(languageTexts[currentLanguage].selectDifficulty, {
size: 100,
fill: 0xFFFFFF
});
difficultyTitle.anchor.set(0.5, 0.5);
LK.gui.center.addChild(difficultyTitle);
difficultyTitle.y = -200;
difficultyTitle.alpha = 0;
// Create background blocks for difficulty buttons
var easyBlock = LK.getAsset('cell', {
anchorX: 0.5,
anchorY: 0.5,
width: 400,
height: 120,
tint: 0x44FF44,
alpha: 0.3
});
LK.gui.center.addChild(easyBlock);
easyBlock.y = -100;
easyBlock.alpha = 0;
var normalBlock = LK.getAsset('cell', {
anchorX: 0.5,
anchorY: 0.5,
width: 400,
height: 120,
tint: 0xFFAA00,
alpha: 0.3
});
LK.gui.center.addChild(normalBlock);
normalBlock.y = 50;
normalBlock.alpha = 0;
var hardBlock = LK.getAsset('cell', {
anchorX: 0.5,
anchorY: 0.5,
width: 400,
height: 120,
tint: 0xFF4444,
alpha: 0.3
});
LK.gui.center.addChild(hardBlock);
hardBlock.y = 200;
hardBlock.alpha = 0;
var easyBtn = new Text2(languageTexts[currentLanguage].easy, {
size: 90,
fill: 0x44FF44
});
easyBtn.anchor.set(0.5, 0.5);
easyBtn.interactive = false;
easyBtn.hitArea = new Rectangle(-150, -45, 300, 90);
LK.gui.center.addChild(easyBtn);
easyBtn.y = -100;
easyBtn.alpha = 0;
var normalBtn = new Text2(languageTexts[currentLanguage].normal, {
size: 90,
fill: 0xFFAA00
});
normalBtn.anchor.set(0.5, 0.5);
normalBtn.interactive = false;
normalBtn.hitArea = new Rectangle(-150, -45, 300, 90);
LK.gui.center.addChild(normalBtn);
normalBtn.y = 50;
normalBtn.alpha = 0;
var hardBtn = new Text2(languageTexts[currentLanguage].hard, {
size: 90,
fill: 0xFF4444
});
hardBtn.anchor.set(0.5, 0.5);
hardBtn.interactive = false;
hardBtn.hitArea = new Rectangle(-150, -45, 300, 90);
LK.gui.center.addChild(hardBtn);
hardBtn.y = 200;
hardBtn.alpha = 0;
// Confirmation dialog elements
var confirmationBg = LK.getAsset('gridBackground', {
anchorX: 0.5,
anchorY: 0.5,
width: 1200,
height: 600,
tint: 0x000000,
alpha: 0.8
});
LK.gui.center.addChild(confirmationBg);
confirmationBg.alpha = 0;
var confirmationText = new Text2('', {
size: 80,
fill: 0xFFFFFF
});
confirmationText.anchor.set(0.5, 0.5);
LK.gui.center.addChild(confirmationText);
confirmationText.y = -50;
confirmationText.alpha = 0;
var yesBtn = new Text2(languageTexts[currentLanguage].yes, {
size: 80,
fill: 0x44FF44
});
yesBtn.anchor.set(0.5, 0.5);
yesBtn.interactive = true;
LK.gui.center.addChild(yesBtn);
yesBtn.x = -150;
yesBtn.y = 100;
yesBtn.alpha = 0;
var noBtn = new Text2(languageTexts[currentLanguage].no, {
size: 80,
fill: 0xFF4444
});
noBtn.anchor.set(0.5, 0.5);
noBtn.interactive = true;
LK.gui.center.addChild(noBtn);
noBtn.x = 150;
noBtn.y = 100;
noBtn.alpha = 0;
// Add hit areas to confirmation dialog buttons
yesBtn.hitArea = new Rectangle(-100, -40, 200, 80);
noBtn.hitArea = new Rectangle(-100, -40, 200, 80);
// Confirmation dialog button handlers
yesBtn.down = function (x, y, obj) {
if (isResetConfirmation) {
// Reset all statistics to zero
gameStats.blueWins = 0;
gameStats.redWins = 0;
gameStats.draws = 0;
// Update storage
storage.blueWins = 0;
storage.redWins = 0;
storage.draws = 0;
// Update display
blueStatsText.setText(languageTexts[currentLanguage].blueWins + gameStats.blueWins);
redStatsText.setText(languageTexts[currentLanguage].redWins + gameStats.redWins);
drawStatsText.setText(languageTexts[currentLanguage].draws + gameStats.draws);
hideConfirmationDialog();
} else if (selectedDifficulty) {
aiDifficulty = selectedDifficulty;
hideConfirmationDialog();
startGame('ai');
}
};
noBtn.down = function (x, y, obj) {
hideConfirmationDialog();
};
// Add glowing animation to blocks
function animateDifficultyBlocks() {
tween(easyBlock, {
alpha: 0.6
}, {
duration: 1000,
easing: tween.easeInOut,
repeat: -1,
yoyo: true
});
tween(normalBlock, {
alpha: 0.6
}, {
duration: 1000,
easing: tween.easeInOut,
repeat: -1,
yoyo: true,
delay: 333
});
tween(hardBlock, {
alpha: 0.6
}, {
duration: 1000,
easing: tween.easeInOut,
repeat: -1,
yoyo: true,
delay: 666
});
}
function showConfirmationDialog(difficulty) {
selectedDifficulty = difficulty;
gameMode = 'confirmation';
isResetConfirmation = false;
var confirmText = '';
if (difficulty === 'easy') {
confirmText = languageTexts[currentLanguage].confirmEasy;
} else if (difficulty === 'normal') {
confirmText = languageTexts[currentLanguage].confirmNormal;
} else if (difficulty === 'hard') {
confirmText = languageTexts[currentLanguage].confirmHard;
}
confirmationText.setText(confirmText);
// Enable confirmation button interactions
yesBtn.interactive = true;
noBtn.interactive = true;
// Show confirmation elements
tween(confirmationBg, {
alpha: 0.8
}, {
duration: 200
});
tween(confirmationText, {
alpha: 1
}, {
duration: 200
});
tween(yesBtn, {
alpha: 1
}, {
duration: 200
});
tween(noBtn, {
alpha: 1
}, {
duration: 200
});
}
function showResetConfirmationDialog() {
isResetConfirmation = true;
gameMode = 'confirmation';
selectedDifficulty = '';
confirmationText.setText(languageTexts[currentLanguage].confirmReset);
// Enable confirmation button interactions
yesBtn.interactive = true;
noBtn.interactive = true;
// Show confirmation elements
tween(confirmationBg, {
alpha: 0.8
}, {
duration: 200
});
tween(confirmationText, {
alpha: 1
}, {
duration: 200
});
tween(yesBtn, {
alpha: 1
}, {
duration: 200
});
tween(noBtn, {
alpha: 1
}, {
duration: 200
});
}
function hideConfirmationDialog() {
if (isResetConfirmation) {
// Return to appropriate game mode when hiding reset confirmation
if (gameBoard.alpha > 0) {
gameMode = isAIMode ? 'ai' : 'twoPlayer';
} else {
gameMode = 'menu';
}
} else {
gameMode = 'difficulty';
}
selectedDifficulty = '';
isResetConfirmation = false;
// Disable confirmation button interactions
yesBtn.interactive = false;
noBtn.interactive = false;
// Hide confirmation elements
tween(confirmationBg, {
alpha: 0
}, {
duration: 200
});
tween(confirmationText, {
alpha: 0
}, {
duration: 200
});
tween(yesBtn, {
alpha: 0
}, {
duration: 200
});
tween(noBtn, {
alpha: 0
}, {
duration: 200
});
}
var vsAIBtn = new Text2(languageTexts[currentLanguage].vsAI, {
size: 100,
fill: 0x00AAFF
});
vsAIBtn.anchor.set(0.5, 0.5);
vsAIBtn.interactive = false;
vsAIBtn.hitArea = new Rectangle(-200, -50, 400, 100);
LK.gui.center.addChild(vsAIBtn);
vsAIBtn.y = 0;
var twoPlayerBtn = new Text2(languageTexts[currentLanguage].twoPlayer, {
size: 100,
fill: 0xFF4444
});
twoPlayerBtn.anchor.set(0.5, 0.5);
twoPlayerBtn.interactive = false;
twoPlayerBtn.hitArea = new Rectangle(-200, -50, 400, 100);
LK.gui.center.addChild(twoPlayerBtn);
twoPlayerBtn.y = 150;
var backBtn = new Text2(languageTexts[currentLanguage].back, {
size: 70,
fill: 0xFFFFFF
});
backBtn.anchor.set(0.5, 0.5);
backBtn.interactive = false;
backBtn.hitArea = new Rectangle(-150, -40, 300, 80);
LK.gui.top.addChild(backBtn);
backBtn.x = 200;
backBtn.y = 220;
backBtn.alpha = 0;
var exitBtn = new Text2(languageTexts[currentLanguage].exit, {
size: 60,
fill: 0xFF0000
});
exitBtn.anchor.set(0.5, 0);
exitBtn.interactive = false;
exitBtn.hitArea = new Rectangle(-80, -30, 160, 60);
LK.gui.top.addChild(exitBtn);
exitBtn.y = 120;
exitBtn.x = 400;
exitBtn.alpha = 0;
// Statistics display elements
var statsContainer = new Container();
LK.gui.bottom.addChild(statsContainer);
statsContainer.y = -180;
statsContainer.alpha = 0;
var blueStatsText = new Text2(languageTexts[currentLanguage].blueWins + gameStats.blueWins, {
size: 45,
fill: 0x00AAFF
});
blueStatsText.anchor.set(0.5, 0);
statsContainer.addChild(blueStatsText);
blueStatsText.y = 0;
blueStatsText.x = -600;
var redStatsText = new Text2(languageTexts[currentLanguage].redWins + gameStats.redWins, {
size: 45,
fill: 0xFF4444
});
redStatsText.anchor.set(0.5, 0);
statsContainer.addChild(redStatsText);
redStatsText.y = 0;
redStatsText.x = 0;
var drawStatsText = new Text2(languageTexts[currentLanguage].draws + gameStats.draws, {
size: 45,
fill: 0xFFFFFF
});
drawStatsText.anchor.set(0.5, 0);
statsContainer.addChild(drawStatsText);
drawStatsText.y = 0;
drawStatsText.x = 600;
var resetStatsBtn = new Text2(languageTexts[currentLanguage].resetStats, {
size: 40,
fill: 0xFF4444
});
resetStatsBtn.anchor.set(0.5, 0);
resetStatsBtn.interactive = true;
resetStatsBtn.hitArea = new Rectangle(-70, -20, 140, 40);
statsContainer.addChild(resetStatsBtn);
resetStatsBtn.y = 70;
resetStatsBtn.x = 0;
// Change Appearance button
var changeAppearanceBtn = new Text2(languageTexts[currentLanguage].changeAppearance, {
size: 60,
fill: 0x00AAFF
});
changeAppearanceBtn.anchor.set(0.5, 0.5);
changeAppearanceBtn.interactive = true;
changeAppearanceBtn.hitArea = new Rectangle(-120, -30, 240, 60);
LK.gui.center.addChild(changeAppearanceBtn);
changeAppearanceBtn.y = -100;
changeAppearanceBtn.alpha = 0;
// Current appearance style display
var currentStyleText = new Text2('', {
size: 50,
fill: 0xFFFFFF
});
currentStyleText.anchor.set(0.5, 0.5);
LK.gui.center.addChild(currentStyleText);
currentStyleText.y = -20;
currentStyleText.alpha = 0;
// Package selection UI elements
var packageTitle = new Text2(languageTexts[currentLanguage].selectPackage, {
size: 100,
fill: 0xFFFFFF
});
packageTitle.anchor.set(0.5, 0.5);
LK.gui.center.addChild(packageTitle);
packageTitle.y = -250;
packageTitle.alpha = 0;
// Package selection buttons
var package1Btn = new Text2(languageTexts[currentLanguage].package1, {
size: 80,
fill: 0x00AAFF
});
package1Btn.anchor.set(0.5, 0.5);
package1Btn.interactive = false;
package1Btn.hitArea = new Rectangle(-120, -40, 240, 80);
LK.gui.center.addChild(package1Btn);
package1Btn.y = -120;
package1Btn.alpha = 0;
var package2Btn = new Text2(languageTexts[currentLanguage].package2, {
size: 80,
fill: 0xFF8800
});
package2Btn.anchor.set(0.5, 0.5);
package2Btn.interactive = false;
package2Btn.hitArea = new Rectangle(-120, -40, 240, 80);
LK.gui.center.addChild(package2Btn);
package2Btn.y = -20;
package2Btn.alpha = 0;
var package3Btn = new Text2(languageTexts[currentLanguage].package3, {
size: 80,
fill: 0x44FF44
});
package3Btn.anchor.set(0.5, 0.5);
package3Btn.interactive = false;
package3Btn.hitArea = new Rectangle(-120, -40, 240, 80);
LK.gui.center.addChild(package3Btn);
package3Btn.y = 80;
package3Btn.alpha = 0;
var package4Btn = new Text2(languageTexts[currentLanguage].package4, {
size: 80,
fill: 0xFF4444
});
package4Btn.anchor.set(0.5, 0.5);
package4Btn.interactive = false;
package4Btn.hitArea = new Rectangle(-120, -40, 240, 80);
LK.gui.center.addChild(package4Btn);
package4Btn.y = 180;
package4Btn.alpha = 0;
var package5Btn = new Text2(languageTexts[currentLanguage].package5, {
size: 80,
fill: 0x00FFFF
});
package5Btn.anchor.set(0.5, 0.5);
package5Btn.interactive = false;
package5Btn.hitArea = new Rectangle(-120, -40, 240, 80);
LK.gui.center.addChild(package5Btn);
package5Btn.y = 280;
package5Btn.alpha = 0;
var package6Btn = new Text2(languageTexts[currentLanguage].package6, {
size: 80,
fill: 0xFF00FF
});
package6Btn.anchor.set(0.5, 0.5);
package6Btn.interactive = false;
package6Btn.hitArea = new Rectangle(-120, -40, 240, 80);
LK.gui.center.addChild(package6Btn);
package6Btn.y = 380;
package6Btn.alpha = 0;
var package7Btn = new Text2(languageTexts[currentLanguage].package7, {
size: 80,
fill: 0x00FF00
});
package7Btn.anchor.set(0.5, 0.5);
package7Btn.interactive = false;
package7Btn.hitArea = new Rectangle(-120, -40, 240, 80);
LK.gui.center.addChild(package7Btn);
package7Btn.y = 480;
package7Btn.alpha = 0;
// Package selection backgrounds
var package1Bg = LK.getAsset('cell', {
anchorX: 0.5,
anchorY: 0.5,
width: 300,
height: 80,
tint: 0x00AAFF,
alpha: 0.2
});
LK.gui.center.addChild(package1Bg);
package1Bg.y = -120;
package1Bg.alpha = 0;
var package2Bg = LK.getAsset('cell', {
anchorX: 0.5,
anchorY: 0.5,
width: 300,
height: 80,
tint: 0xFF8800,
alpha: 0.2
});
LK.gui.center.addChild(package2Bg);
package2Bg.y = -20;
package2Bg.alpha = 0;
var package3Bg = LK.getAsset('cell', {
anchorX: 0.5,
anchorY: 0.5,
width: 300,
height: 80,
tint: 0x44FF44,
alpha: 0.2
});
LK.gui.center.addChild(package3Bg);
package3Bg.y = 80;
package3Bg.alpha = 0;
var package4Bg = LK.getAsset('cell', {
anchorX: 0.5,
anchorY: 0.5,
width: 300,
height: 80,
tint: 0xFF4444,
alpha: 0.2
});
LK.gui.center.addChild(package4Bg);
package4Bg.y = 180;
package4Bg.alpha = 0;
var package5Bg = LK.getAsset('cell', {
anchorX: 0.5,
anchorY: 0.5,
width: 300,
height: 80,
tint: 0x00FFFF,
alpha: 0.2
});
LK.gui.center.addChild(package5Bg);
package5Bg.y = 280;
package5Bg.alpha = 0;
var package6Bg = LK.getAsset('cell', {
anchorX: 0.5,
anchorY: 0.5,
width: 300,
height: 80,
tint: 0xFF00FF,
alpha: 0.2
});
LK.gui.center.addChild(package6Bg);
package6Bg.y = 380;
package6Bg.alpha = 0;
var package7Bg = LK.getAsset('cell', {
anchorX: 0.5,
anchorY: 0.5,
width: 300,
height: 80,
tint: 0x00FF00,
alpha: 0.2
});
LK.gui.center.addChild(package7Bg);
package7Bg.y = 480;
package7Bg.alpha = 0;
// Language toggle functionality
languageBtn.interactive = true; // Always interactive
languageBtn.hitArea = new Rectangle(-100, -40, 200, 80);
languageBtn.down = function (x, y, obj) {
// Always allow language switching regardless of game state
currentLanguage = currentLanguage === 'tr' ? 'en' : 'tr';
storage.language = currentLanguage;
updateLanguageTexts();
};
// Menu button handlers
vsAIBtn.down = function (x, y, obj) {
if (gameMode === 'menu') {
showDifficultySelection();
}
};
twoPlayerBtn.down = function (x, y, obj) {
if (gameMode === 'menu') {
startGame('twoPlayer');
}
};
// Difficulty button handlers
easyBtn.down = function (x, y, obj) {
if (gameMode === 'difficulty') {
showConfirmationDialog('easy');
}
};
normalBtn.down = function (x, y, obj) {
if (gameMode === 'difficulty') {
showConfirmationDialog('normal');
}
};
hardBtn.down = function (x, y, obj) {
if (gameMode === 'difficulty') {
showConfirmationDialog('hard');
}
};
backBtn.down = function (x, y, obj) {
if (gameMode === 'confirmation') {
hideConfirmationDialog();
} else if (gameMode === 'difficulty') {
showMenu();
} else if (gameMode === 'settings') {
showMenu();
} else if (gameMode === 'packages') {
showSettingsMenu();
} else if (gameMode !== 'menu') {
resetGame();
showMenu();
}
};
exitBtn.down = function (x, y, obj) {
if (gameMode !== 'menu') {
resetGame();
showMenu();
}
};
resetStatsBtn.down = function (x, y, obj) {
if (statsContainer.alpha > 0) {
// Show reset confirmation dialog
showResetConfirmationDialog();
}
};
changeAppearanceBtn.down = function (x, y, obj) {
if (gameMode === 'settings') {
showPackageSelection();
}
};
// Package selection button handlers
package1Btn.down = function (x, y, obj) {
if (gameMode === 'packages') {
selectPackage(0);
}
};
package2Btn.down = function (x, y, obj) {
if (gameMode === 'packages') {
selectPackage(1);
}
};
package3Btn.down = function (x, y, obj) {
if (gameMode === 'packages') {
selectPackage(2);
}
};
package4Btn.down = function (x, y, obj) {
if (gameMode === 'packages') {
selectPackage(3);
}
};
package5Btn.down = function (x, y, obj) {
if (gameMode === 'packages') {
selectPackage(4);
}
};
package6Btn.down = function (x, y, obj) {
if (gameMode === 'packages') {
selectPackage(5);
}
};
package7Btn.down = function (x, y, obj) {
if (gameMode === 'packages') {
selectPackage(6);
}
};
settingsBtn.down = function (x, y, obj) {
if (gameMode === 'menu') {
showSettingsMenu();
}
};
function showPackageSelection() {
gameMode = 'packages';
// Hide settings menu
changeAppearanceBtn.alpha = 0;
changeAppearanceBtn.interactive = false;
// Hide current style text
currentStyleText.alpha = 0;
// Show package selection elements
packageTitle.alpha = 1;
package1Btn.alpha = 1;
package2Btn.alpha = 1;
package3Btn.alpha = 1;
package4Btn.alpha = 1;
package5Btn.alpha = 1;
package6Btn.alpha = 1;
package7Btn.alpha = 1;
package1Bg.alpha = 0.2;
package2Bg.alpha = 0.2;
package3Bg.alpha = 0.2;
package4Bg.alpha = 0.2;
package5Bg.alpha = 0.2;
package6Bg.alpha = 0.2;
package7Bg.alpha = 0.2;
// Enable package button interactions
package1Btn.interactive = true;
package2Btn.interactive = true;
package3Btn.interactive = true;
package4Btn.interactive = true;
package5Btn.interactive = true;
package6Btn.interactive = true;
package7Btn.interactive = true;
// Highlight current package
highlightCurrentPackage();
}
function selectPackage(packageIndex) {
currentAppearanceStyle = packageIndex;
storage.appearanceStyle = currentAppearanceStyle;
// If there's an active game, reset it to apply new styles
if (gameBoard.alpha > 0) {
resetGame();
}
// Update package highlight
highlightCurrentPackage();
// Go back to settings menu after selection
showSettingsMenu();
}
function highlightCurrentPackage() {
// Reset all backgrounds
package1Bg.alpha = 0.2;
package2Bg.alpha = 0.2;
package3Bg.alpha = 0.2;
package4Bg.alpha = 0.2;
package5Bg.alpha = 0.2;
package6Bg.alpha = 0.2;
package7Bg.alpha = 0.2;
// Highlight current selection
if (currentAppearanceStyle === 0) {
package1Bg.alpha = 0.6;
} else if (currentAppearanceStyle === 1) {
package2Bg.alpha = 0.6;
} else if (currentAppearanceStyle === 2) {
package3Bg.alpha = 0.6;
} else if (currentAppearanceStyle === 3) {
package4Bg.alpha = 0.6;
} else if (currentAppearanceStyle === 4) {
package5Bg.alpha = 0.6;
} else if (currentAppearanceStyle === 5) {
package6Bg.alpha = 0.6;
} else if (currentAppearanceStyle === 6) {
package7Bg.alpha = 0.6;
}
}
function updateLanguageTexts() {
blueTurnText.setText(languageTexts[currentLanguage].blueTurn);
redTurnText.setText(languageTexts[currentLanguage].redTurn);
playAgainBtn.setText(languageTexts[currentLanguage].playAgain);
languageBtn.setText(languageTexts[currentLanguage === 'tr' ? 'en' : 'tr'].language);
menuTitle.setText(languageTexts[currentLanguage].selectMode);
vsAIBtn.setText(languageTexts[currentLanguage].vsAI);
twoPlayerBtn.setText(languageTexts[currentLanguage].twoPlayer);
backBtn.setText(languageTexts[currentLanguage].back);
exitBtn.setText(languageTexts[currentLanguage].exit);
difficultyTitle.setText(languageTexts[currentLanguage].selectDifficulty);
easyBtn.setText(languageTexts[currentLanguage].easy);
normalBtn.setText(languageTexts[currentLanguage].normal);
hardBtn.setText(languageTexts[currentLanguage].hard);
yesBtn.setText(languageTexts[currentLanguage].yes);
noBtn.setText(languageTexts[currentLanguage].no);
settingsBtn.setText(languageTexts[currentLanguage].settings);
changeAppearanceBtn.setText(languageTexts[currentLanguage].changeAppearance);
packageTitle.setText(languageTexts[currentLanguage].selectPackage);
package1Btn.setText(languageTexts[currentLanguage].package1);
package2Btn.setText(languageTexts[currentLanguage].package2);
package3Btn.setText(languageTexts[currentLanguage].package3);
package4Btn.setText(languageTexts[currentLanguage].package4);
package5Btn.setText(languageTexts[currentLanguage].package5);
package6Btn.setText(languageTexts[currentLanguage].package6);
package7Btn.setText(languageTexts[currentLanguage].package7);
// Update winner/draw text if game is over
if (gameOver && statusText.alpha > 0) {
var currentText = statusText.text;
// Check for all possible winner texts based on styles
var isBlueWin = false;
var isRedWin = false;
var isDraw = false;
var isXWin = false;
var isOWin = false;
// Check classic wins
if (currentText === languageTexts.tr.blueWin || currentText === languageTexts.en.blueWin) isBlueWin = true;
if (currentText === languageTexts.tr.redWin || currentText === languageTexts.en.redWin) isRedWin = true;
if (currentText === languageTexts.tr.draw || currentText === languageTexts.en.draw) isDraw = true;
// Check Tom ve Jerry wins
if (currentText === 'TOM KAZANDI!' || currentText === 'TOM WON!') isXWin = true;
if (currentText === 'JERRY KAZANDI!' || currentText === 'JERRY WON!') isOWin = true;
// Check Batman vs Joker wins
if (currentText === 'BATMAN KAZANDI!' || currentText === 'BATMAN WON!') isXWin = true;
if (currentText === 'JOKER KAZANDI!' || currentText === 'JOKER WON!') isOWin = true;
// Check Ronaldo vs. Messi wins
if (currentText === 'RONALDO KAZANDI!' || currentText === 'RONALDO WON!') isXWin = true;
if (currentText === 'MESSI KAZANDI!' || currentText === 'MESSI WON!') isOWin = true;
// Check Spiderman vs Venom wins
if (currentText === 'SPIDERMAN KAZANDI!' || currentText === 'SPIDERMAN WON!') isXWin = true;
if (currentText === 'VENOM KAZANDI!' || currentText === 'VENOM WON!') isOWin = true;
// Check Steve vs Alex wins
if (currentText === 'STEVE KAZANDI!' || currentText === 'STEVE WON!') isXWin = true;
if (currentText === 'ALEX KAZANDI!' || currentText === 'ALEX WON!') isOWin = true;
// Update text based on current style and language
if (isBlueWin || isXWin) {
if (currentAppearanceStyle === 0) {
statusText.setText(languageTexts[currentLanguage].blueWin);
} else if (currentAppearanceStyle === 1) {
statusText.setText(currentLanguage === 'tr' ? 'TOM KAZANDI!' : 'TOM WON!');
} else if (currentAppearanceStyle === 2) {
statusText.setText(currentLanguage === 'tr' ? 'BATMAN KAZANDI!' : 'BATMAN WON!');
} else if (currentAppearanceStyle === 3) {
statusText.setText(currentLanguage === 'tr' ? 'RONALDO KAZANDI!' : 'RONALDO WON!');
} else if (currentAppearanceStyle === 4) {
statusText.setText(currentLanguage === 'tr' ? 'SPIDERMAN KAZANDI!' : 'SPIDERMAN WON!');
} else if (currentAppearanceStyle === 5) {
statusText.setText(currentLanguage === 'tr' ? 'STEVE KAZANDI!' : 'STEVE WON!');
} else if (currentAppearanceStyle === 6) {
statusText.setText(currentLanguage === 'tr' ? 'STEVE KAZANDI!' : 'STEVE WON!');
}
} else if (isRedWin || isOWin) {
if (currentAppearanceStyle === 0) {
statusText.setText(languageTexts[currentLanguage].redWin);
} else if (currentAppearanceStyle === 1) {
statusText.setText(currentLanguage === 'tr' ? 'JERRY KAZANDI!' : 'JERRY WON!');
} else if (currentAppearanceStyle === 2) {
statusText.setText(currentLanguage === 'tr' ? 'JOKER KAZANDI!' : 'JOKER WON!');
} else if (currentAppearanceStyle === 3) {
statusText.setText(currentLanguage === 'tr' ? 'MESSI KAZANDI!' : 'MESSI WON!');
} else if (currentAppearanceStyle === 4) {
statusText.setText(currentLanguage === 'tr' ? 'VENOM KAZANDI!' : 'VENOM WON!');
} else if (currentAppearanceStyle === 5) {
statusText.setText(currentLanguage === 'tr' ? 'ALEX KAZANDI!' : 'ALEX WON!');
} else if (currentAppearanceStyle === 6) {
statusText.setText(currentLanguage === 'tr' ? 'ALEX KAZANDI!' : 'ALEX WON!');
}
} else if (isDraw) {
statusText.setText(languageTexts[currentLanguage].draw);
}
}
// Update statistics display
blueStatsText.setText(languageTexts[currentLanguage].blueWins + gameStats.blueWins);
redStatsText.setText(languageTexts[currentLanguage].redWins + gameStats.redWins);
drawStatsText.setText(languageTexts[currentLanguage].draws + gameStats.draws);
resetStatsBtn.setText(languageTexts[currentLanguage].resetStats);
// Update current style text if visible
if (currentStyleText.alpha > 0) {
var currentStyleName = '';
if (currentAppearanceStyle === 0) {
currentStyleName = languageTexts[currentLanguage].package1;
} else if (currentAppearanceStyle === 1) {
currentStyleName = languageTexts[currentLanguage].package2;
} else if (currentAppearanceStyle === 2) {
currentStyleName = languageTexts[currentLanguage].package3;
} else if (currentAppearanceStyle === 3) {
currentStyleName = languageTexts[currentLanguage].package4;
} else if (currentAppearanceStyle === 4) {
currentStyleName = languageTexts[currentLanguage].package5;
} else if (currentAppearanceStyle === 5) {
currentStyleName = languageTexts[currentLanguage].package6;
} else if (currentAppearanceStyle === 6) {
currentStyleName = languageTexts[currentLanguage].package7;
}
currentStyleText.setText(languageTexts[currentLanguage].selected + currentStyleName);
}
// Reposition statistics horizontally to display side by side with better spacing
blueStatsText.y = 0;
blueStatsText.x = -500;
redStatsText.y = 0;
redStatsText.x = 0;
drawStatsText.y = 0;
drawStatsText.x = 500;
}
// Add logo in top-left corner
var logoImg = LK.getAsset('logo', {
anchorX: 0,
anchorY: 0,
scaleX: 0.5,
scaleY: 0.5
});
LK.gui.topLeft.addChild(logoImg);
logoImg.x = 120;
logoImg.y = 60;
// Add website text in the center
var websiteText = new Text2('vayabi.net', {
size: 80,
fill: 0xFFFFFF
});
websiteText.anchor.set(0.5, 0.5);
LK.gui.center.addChild(websiteText);
websiteText.y = 600;
websiteText.alpha = 0.7;
// Start in menu mode
showMenu();
function updateTurnDisplay() {
if (gameMode === 'menu' || gameOver) {
blueTurnText.alpha = 0;
redTurnText.alpha = 0;
} else if (currentPlayer === 1) {
blueTurnText.alpha = 1;
redTurnText.alpha = 0;
} else {
blueTurnText.alpha = 0;
redTurnText.alpha = 1;
}
}
function showMenu() {
gameMode = 'menu';
gameBoard.alpha = 0;
settingsBtn.alpha = 1;
settingsBtn.interactive = true;
menuTitle.alpha = 1;
vsAIBtn.alpha = 1;
twoPlayerBtn.alpha = 1;
// Enable main menu interactions
vsAIBtn.interactive = true;
twoPlayerBtn.interactive = true;
blueTurnText.alpha = 0;
redTurnText.alpha = 0;
statusText.alpha = 0;
playAgainBtn.alpha = 0;
playAgainBtn.interactive = false;
playAgainBg.alpha = 0;
backBtn.alpha = 0;
backBtn.interactive = false;
exitBtn.alpha = 0;
exitBtn.interactive = false;
// Hide difficulty selection
difficultyTitle.alpha = 0;
easyBtn.alpha = 0;
normalBtn.alpha = 0;
hardBtn.alpha = 0;
// Disable difficulty button interactions
easyBtn.interactive = false;
normalBtn.interactive = false;
hardBtn.interactive = false;
// Hide blocks
// Stop any active animations on difficulty blocks
tween.stop(easyBlock);
tween.stop(normalBlock);
tween.stop(hardBlock);
easyBlock.alpha = 0;
normalBlock.alpha = 0;
hardBlock.alpha = 0;
// Hide confirmation dialog
confirmationBg.alpha = 0;
confirmationText.alpha = 0;
yesBtn.alpha = 0;
noBtn.alpha = 0;
// Disable confirmation dialog interactions
yesBtn.interactive = false;
noBtn.interactive = false;
// Hide statistics in menu
statsContainer.alpha = 0;
// Hide appearance button
changeAppearanceBtn.alpha = 0;
changeAppearanceBtn.interactive = false;
// Hide current style text
currentStyleText.alpha = 0;
// Hide package selection elements
packageTitle.alpha = 0;
package1Btn.alpha = 0;
package2Btn.alpha = 0;
package3Btn.alpha = 0;
package4Btn.alpha = 0;
package5Btn.alpha = 0;
package6Btn.alpha = 0;
package7Btn.alpha = 0;
package1Bg.alpha = 0;
package2Bg.alpha = 0;
package3Bg.alpha = 0;
package4Bg.alpha = 0;
package5Bg.alpha = 0;
package6Bg.alpha = 0;
package7Bg.alpha = 0;
// Disable package button interactions
package1Btn.interactive = false;
package2Btn.interactive = false;
package3Btn.interactive = false;
package4Btn.interactive = false;
package5Btn.interactive = false;
package6Btn.interactive = false;
package7Btn.interactive = false;
}
function showSettingsMenu() {
gameMode = 'settings';
// Hide main menu
settingsBtn.alpha = 0;
settingsBtn.interactive = false;
menuTitle.alpha = 0;
vsAIBtn.alpha = 0;
twoPlayerBtn.alpha = 0;
vsAIBtn.interactive = false;
twoPlayerBtn.interactive = false;
// Show back button and language button more prominently
backBtn.alpha = 1;
backBtn.interactive = true;
// Show appearance change button
changeAppearanceBtn.alpha = 1;
changeAppearanceBtn.interactive = true;
// Show current appearance style
var currentStyleName = '';
if (currentAppearanceStyle === 0) {
currentStyleName = languageTexts[currentLanguage].package1;
} else if (currentAppearanceStyle === 1) {
currentStyleName = languageTexts[currentLanguage].package2;
} else if (currentAppearanceStyle === 2) {
currentStyleName = languageTexts[currentLanguage].package3;
} else if (currentAppearanceStyle === 3) {
currentStyleName = languageTexts[currentLanguage].package4;
} else if (currentAppearanceStyle === 4) {
currentStyleName = languageTexts[currentLanguage].package5;
} else if (currentAppearanceStyle === 5) {
currentStyleName = languageTexts[currentLanguage].package6;
} else if (currentAppearanceStyle === 6) {
currentStyleName = languageTexts[currentLanguage].package7;
}
currentStyleText.setText(languageTexts[currentLanguage].selected + currentStyleName);
currentStyleText.alpha = 1;
// Hide package selection elements
packageTitle.alpha = 0;
package1Btn.alpha = 0;
package2Btn.alpha = 0;
package3Btn.alpha = 0;
package4Btn.alpha = 0;
package5Btn.alpha = 0;
package6Btn.alpha = 0;
package7Btn.alpha = 0;
package1Bg.alpha = 0;
package2Bg.alpha = 0;
package3Bg.alpha = 0;
package4Bg.alpha = 0;
package5Bg.alpha = 0;
package6Bg.alpha = 0;
package7Bg.alpha = 0;
// Disable package button interactions
package1Btn.interactive = false;
package2Btn.interactive = false;
package3Btn.interactive = false;
package4Btn.interactive = false;
package5Btn.interactive = false;
package6Btn.interactive = false;
package7Btn.interactive = false;
}
function showDifficultySelection() {
gameMode = 'difficulty';
// Hide main menu
menuTitle.alpha = 0;
vsAIBtn.alpha = 0;
twoPlayerBtn.alpha = 0;
// Disable main menu interactions
vsAIBtn.interactive = false;
twoPlayerBtn.interactive = false;
// Hide settings button in difficulty selection
settingsBtn.alpha = 0;
settingsBtn.interactive = false;
// Show difficulty selection
difficultyTitle.alpha = 1;
easyBtn.alpha = 1;
normalBtn.alpha = 1;
hardBtn.alpha = 1;
backBtn.alpha = 1;
// Enable difficulty button interactions
easyBtn.interactive = true;
normalBtn.interactive = true;
hardBtn.interactive = true;
backBtn.interactive = true;
// Show and animate blocks
easyBlock.alpha = 0.3;
normalBlock.alpha = 0.3;
hardBlock.alpha = 0.3;
animateDifficultyBlocks();
}
function startGame(mode) {
gameMode = mode;
isAIMode = mode === 'ai';
gameBoard.alpha = 1;
settingsBtn.alpha = 0;
settingsBtn.interactive = false;
menuTitle.alpha = 0;
vsAIBtn.alpha = 0;
twoPlayerBtn.alpha = 0;
// Disable menu interactions
vsAIBtn.interactive = false;
twoPlayerBtn.interactive = false;
// Hide difficulty selection
difficultyTitle.alpha = 0;
easyBtn.alpha = 0;
normalBtn.alpha = 0;
hardBtn.alpha = 0;
// Disable difficulty button interactions
easyBtn.interactive = false;
normalBtn.interactive = false;
hardBtn.interactive = false;
// Hide blocks
easyBlock.alpha = 0;
normalBlock.alpha = 0;
hardBlock.alpha = 0;
// Hide confirmation dialog
confirmationBg.alpha = 0;
confirmationText.alpha = 0;
yesBtn.alpha = 0;
noBtn.alpha = 0;
// Disable confirmation dialog interactions
yesBtn.interactive = false;
noBtn.interactive = false;
// Hide back button in all game modes once game starts
backBtn.alpha = 0;
backBtn.interactive = false;
exitBtn.alpha = 1;
// Enable exit button interaction
exitBtn.interactive = true;
// In AI mode, player (1) always starts first
if (isAIMode) {
currentPlayer = 1;
} else {
// In two player mode, random start
currentPlayer = Math.random() < 0.5 ? 1 : 2;
}
updateTurnDisplay();
// Hide settings and package elements
changeAppearanceBtn.alpha = 0;
changeAppearanceBtn.interactive = false;
// Hide current style text
currentStyleText.alpha = 0;
packageTitle.alpha = 0;
package1Btn.alpha = 0;
package2Btn.alpha = 0;
package3Btn.alpha = 0;
package4Btn.alpha = 0;
package5Btn.alpha = 0;
package6Btn.alpha = 0;
package7Btn.alpha = 0;
package1Bg.alpha = 0;
package2Bg.alpha = 0;
package3Bg.alpha = 0;
package4Bg.alpha = 0;
package5Bg.alpha = 0;
package6Bg.alpha = 0;
package7Bg.alpha = 0;
// Disable package button interactions
package1Btn.interactive = false;
package2Btn.interactive = false;
package3Btn.interactive = false;
package4Btn.interactive = false;
package5Btn.interactive = false;
package6Btn.interactive = false;
package7Btn.interactive = false;
// Show statistics during gameplay
statsContainer.alpha = 1;
}
function checkWin() {
var winner = 0;
var winPositions = [];
// Check rows
for (var row = 0; row < 3; row++) {
if (grid[row][0].value !== 0 && grid[row][0].value === grid[row][1].value && grid[row][1].value === grid[row][2].value) {
winner = grid[row][0].value;
winPositions = [{
row: row,
col: 0
}, {
row: row,
col: 1
}, {
row: row,
col: 2
}];
break;
}
}
// Check columns
if (winner === 0) {
for (var col = 0; col < 3; col++) {
if (grid[0][col].value !== 0 && grid[0][col].value === grid[1][col].value && grid[1][col].value === grid[2][col].value) {
winner = grid[0][col].value;
winPositions = [{
row: 0,
col: col
}, {
row: 1,
col: col
}, {
row: 2,
col: col
}];
break;
}
}
}
// Check diagonals
if (winner === 0) {
if (grid[0][0].value !== 0 && grid[0][0].value === grid[1][1].value && grid[1][1].value === grid[2][2].value) {
winner = grid[0][0].value;
winPositions = [{
row: 0,
col: 0
}, {
row: 1,
col: 1
}, {
row: 2,
col: 2
}];
} else if (grid[0][2].value !== 0 && grid[0][2].value === grid[1][1].value && grid[1][1].value === grid[2][0].value) {
winner = grid[0][2].value;
winPositions = [{
row: 0,
col: 2
}, {
row: 1,
col: 1
}, {
row: 2,
col: 0
}];
}
}
if (winner !== 0) {
gameOver = true;
showWinner(winner, winPositions);
return;
}
// Check for draw
var isDraw = true;
for (var r = 0; r < 3; r++) {
for (var c = 0; c < 3; c++) {
if (grid[r][c].value === 0) {
isDraw = false;
break;
}
}
if (!isDraw) break;
}
if (isDraw) {
gameOver = true;
showDraw();
}
}
function showWinner(winner, positions) {
LK.getSound('win').play();
// Update statistics
if (winner === 1) {
gameStats.blueWins++;
storage.blueWins = gameStats.blueWins;
} else {
gameStats.redWins++;
storage.redWins = gameStats.redWins;
}
// Update statistics display
blueStatsText.setText(languageTexts[currentLanguage].blueWins + gameStats.blueWins);
redStatsText.setText(languageTexts[currentLanguage].redWins + gameStats.redWins);
// Custom winner messages based on appearance style
var winnerText = '';
if (currentAppearanceStyle === 0) {
// Klasik X-O
winnerText = winner === 1 ? languageTexts[currentLanguage].blueWin : languageTexts[currentLanguage].redWin;
} else if (currentAppearanceStyle === 1) {
// Tom ve Jerry
if (currentLanguage === 'tr') {
winnerText = winner === 1 ? 'TOM KAZANDI!' : 'JERRY KAZANDI!';
} else {
winnerText = winner === 1 ? 'TOM WON!' : 'JERRY WON!';
}
} else if (currentAppearanceStyle === 2) {
// Batman vs Joker
if (currentLanguage === 'tr') {
winnerText = winner === 1 ? 'BATMAN KAZANDI!' : 'JOKER KAZANDI!';
} else {
winnerText = winner === 1 ? 'BATMAN WON!' : 'JOKER WON!';
}
} else if (currentAppearanceStyle === 3) {
// Ronaldo vs. Messi
if (currentLanguage === 'tr') {
winnerText = winner === 1 ? 'RONALDO KAZANDI!' : 'MESSI KAZANDI!';
} else {
winnerText = winner === 1 ? 'RONALDO WON!' : 'MESSI WON!';
}
} else if (currentAppearanceStyle === 4) {
// Spiderman vs Venom
if (currentLanguage === 'tr') {
winnerText = winner === 1 ? 'SPIDERMAN KAZANDI!' : 'VENOM KAZANDI!';
} else {
winnerText = winner === 1 ? 'SPIDERMAN WON!' : 'VENOM WON!';
}
} else if (currentAppearanceStyle === 5) {
// Steve vs Alex
if (currentLanguage === 'tr') {
winnerText = winner === 1 ? 'STEVE KAZANDI!' : 'ALEX KAZANDI!';
} else {
winnerText = winner === 1 ? 'STEVE WON!' : 'ALEX WON!';
}
} else if (currentAppearanceStyle === 6) {
// Steve vs Alex
if (currentLanguage === 'tr') {
winnerText = winner === 1 ? 'STEVE KAZANDI!' : 'ALEX KAZANDI!';
} else {
winnerText = winner === 1 ? 'STEVE WON!' : 'ALEX WON!';
}
}
var winnerColor = 0x000000; // Black color
statusText.setText(winnerText);
statusText.fill = winnerColor;
statusText.alpha = 1;
blueTurnText.alpha = 0;
redTurnText.alpha = 0;
// Show win line
winLine = gameBoard.addChild(new WinLine());
var startPos = grid[positions[0].row][positions[0].col];
var endPos = grid[positions[2].row][positions[2].col];
var lineColor = winner === 1 ? 0x00aaff : 0xff4444;
winLine.showWinLine(startPos.x, startPos.y, endPos.x, endPos.y, lineColor);
// Show play again button with background
playAgainBtn.interactive = true;
tween(playAgainBg, {
alpha: 0.9
}, {
duration: 500
});
tween(playAgainBtn, {
alpha: 1
}, {
duration: 500
});
// Add pulsing animation to make it more prominent
tween(playAgainBg, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 800,
easing: tween.easeInOut,
repeat: -1,
yoyo: true
});
}
function showDraw() {
// Update statistics
gameStats.draws++;
storage.draws = gameStats.draws;
// Update statistics display
drawStatsText.setText(languageTexts[currentLanguage].draws + gameStats.draws);
statusText.setText(languageTexts[currentLanguage].draw);
statusText.fill = 0x000000; // Black color
statusText.alpha = 1;
blueTurnText.alpha = 0;
redTurnText.alpha = 0;
// Show play again button with background
playAgainBtn.interactive = true;
tween(playAgainBg, {
alpha: 0.9
}, {
duration: 500
});
tween(playAgainBtn, {
alpha: 1
}, {
duration: 500
});
// Add pulsing animation to make it more prominent
tween(playAgainBg, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 800,
easing: tween.easeInOut,
repeat: -1,
yoyo: true
});
}
function makeAIMove() {
if (gameOver || currentPlayer !== 2) return;
// Extra validation for game state
if (!isAIMode || gameMode !== 'ai') return;
// Don't proceed if AI is already processing
if (aiProcessing) return;
// Set AI processing flag to prevent consecutive moves
aiProcessing = true;
// Add safety timeout to clear flag in case of errors
var safetyTimeout = LK.setTimeout(function () {
if (aiProcessing) {
console.log("AI safety timeout triggered - clearing processing flag");
aiProcessing = false; // Safety clear after 5 seconds
}
}, 5000);
// Variable thinking time based on difficulty
var minTime, maxTime;
if (aiDifficulty === 'easy') {
minTime = 300;
maxTime = 800;
} else if (aiDifficulty === 'normal') {
minTime = 500;
maxTime = 1200;
} else {
// hard
minTime = 800;
maxTime = 2000;
}
var thinkingTime = minTime + Math.floor(Math.random() * (maxTime - minTime));
// Use setTimeout to yield frame and prevent blocking
LK.setTimeout(function () {
// Clear the safety timeout since we're now processing
if (safetyTimeout) {
LK.clearTimeout(safetyTimeout);
safetyTimeout = null;
}
// Recheck game state after timeout - ensure AI flag is always cleared
if (gameOver || currentPlayer !== 2 || !isAIMode || gameMode !== 'ai') {
aiProcessing = false;
return;
}
// Additional validation to prevent AI moves during player turn
if (isAIMode && currentPlayer === 1) {
aiProcessing = false;
return;
}
// Extra safety check - if game state is invalid, clear flag
if (!isAIMode || gameMode !== 'ai') {
aiProcessing = false;
return;
}
// Find best move using difficulty-specific strategy
var bestMove = findBestMove();
var moveSuccess = false;
// Validate that we have a valid move and it's still empty
if (bestMove && bestMove.value === 0) {
// Validate coordinates are within bounds
if (bestMove.row >= 0 && bestMove.row < 3 && bestMove.col >= 0 && bestMove.col < 3) {
// Double check the cell is still valid before AI places marker
var targetCell = grid[bestMove.row][bestMove.col];
if (targetCell && targetCell.value === 0 && !gameOver && currentPlayer === 2 && !targetCell.marker) {
if (targetCell.placeMarker(2, function () {
// This callback runs after the AI marker animation completes
checkWin();
if (!gameOver) {
currentPlayer = 1;
updateTurnDisplay();
}
// Clear AI processing flag after move is complete
aiProcessing = false;
})) {
moveSuccess = true;
}
}
}
}
// If the best move failed for any reason, find any empty cell as fallback
if (!moveSuccess && !gameOver && currentPlayer === 2) {
var emptyCells = [];
for (var row = 0; row < 3; row++) {
for (var col = 0; col < 3; col++) {
if (grid[row][col].value === 0 && !grid[row][col].marker) {
emptyCells.push(grid[row][col]);
}
}
}
// Try to place marker on any empty cell
if (emptyCells.length > 0) {
var fallbackCell = emptyCells[Math.floor(Math.random() * emptyCells.length)];
if (fallbackCell.placeMarker(2, function () {
// This callback runs after the fallback AI marker animation completes
checkWin();
if (!gameOver) {
currentPlayer = 1;
updateTurnDisplay();
}
// Clear AI processing flag after move is complete
aiProcessing = false;
})) {
moveSuccess = true;
}
}
}
// If no move was made, clear the processing flag
if (!moveSuccess) {
aiProcessing = false;
}
}, thinkingTime);
}
function findBestMove() {
var emptyCells = [];
var winningMoves = [];
var blockingMoves = [];
var forkMoves = [];
var blockForkMoves = [];
var cornerCells = [];
var edgeCells = [];
var validCells = [];
// Collect all valid empty cells
for (var row = 0; row < 3; row++) {
for (var col = 0; col < 3; col++) {
var cell = grid[row][col];
if (cell && cell.value === 0) {
emptyCells.push(cell);
validCells.push(cell);
// Categorize cell positions
if ((row === 0 || row === 2) && (col === 0 || col === 2)) {
cornerCells.push(cell);
} else if (row === 1 && col === 1) {
// Center cell - handled separately
} else {
edgeCells.push(cell);
}
}
}
}
// Early exit if no valid moves
if (validCells.length === 0) {
return null;
}
// Ensure we always have at least one valid cell to return
if (emptyCells.length === 0) {
return null;
}
// Easy mode: Make deliberate mistakes and play suboptimally
if (aiDifficulty === 'easy') {
// 70% chance to make a completely random move
if (Math.random() < 0.7) {
return validCells[Math.floor(Math.random() * validCells.length)];
}
// 20% chance to avoid winning moves (make mistakes)
if (Math.random() < 0.2) {
var nonWinningMoves = [];
for (var i = 0; i < emptyCells.length; i++) {
var cell = emptyCells[i];
cell.value = 2;
if (!checkWinCondition(2)) {
nonWinningMoves.push(cell);
}
cell.value = 0;
}
if (nonWinningMoves.length > 0) {
return nonWinningMoves[Math.floor(Math.random() * nonWinningMoves.length)];
}
}
// 10% chance to miss blocking player wins
if (Math.random() < 0.1) {
var nonBlockingMoves = [];
for (var i = 0; i < emptyCells.length; i++) {
var cell = emptyCells[i];
cell.value = 1;
if (!checkWinCondition(1)) {
nonBlockingMoves.push(cell);
}
cell.value = 0;
}
if (nonBlockingMoves.length > 0) {
return nonBlockingMoves[Math.floor(Math.random() * nonBlockingMoves.length)];
}
}
// Default: play randomly from all valid moves
return validCells[Math.floor(Math.random() * validCells.length)];
}
// Normal mode: Balanced play with occasional mistakes
if (aiDifficulty === 'normal') {
// Priority 1: Check if AI can win immediately
for (var i = 0; i < emptyCells.length; i++) {
var cell = emptyCells[i];
cell.value = 2;
if (checkWinCondition(2)) {
cell.value = 0;
return cell;
}
cell.value = 0;
}
// Priority 2: Block player from winning
for (var i = 0; i < emptyCells.length; i++) {
var cell = emptyCells[i];
cell.value = 1;
if (checkWinCondition(1)) {
cell.value = 0;
if (Math.random() > 0.02) {
return cell;
}
}
cell.value = 0;
}
// Priority 3: Create forks
if (Math.random() < 0.85) {
forkMoves = checkForFork(2);
if (forkMoves.length > 0) {
return forkMoves[0];
}
}
// Priority 4: Block player forks
if (Math.random() < 0.8) {
var playerForkMoves = checkForFork(1);
if (playerForkMoves.length > 0) {
if (playerForkMoves.length === 1) {
return playerForkMoves[0];
} else {
for (var i = 0; i < emptyCells.length; i++) {
var cell = emptyCells[i];
cell.value = 2;
var createsThreats = false;
for (var j = 0; j < emptyCells.length; j++) {
if (i !== j) {
var testCell = emptyCells[j];
testCell.value = 2;
if (checkWinCondition(2)) {
createsThreats = true;
}
testCell.value = 0;
}
}
cell.value = 0;
if (createsThreats) {
return cell;
}
}
return playerForkMoves[0];
}
}
}
// Priority 5: Basic strategy
if (Math.random() < 0.7) {
var strategicMoves = [];
if (grid[1][1].value === 0) {
strategicMoves.push(grid[1][1]);
strategicMoves.push(grid[1][1]);
}
for (var i = 0; i < cornerCells.length; i++) {
strategicMoves.push(cornerCells[i]);
}
if (strategicMoves.length > 0) {
return strategicMoves[Math.floor(Math.random() * strategicMoves.length)];
}
}
if (emptyCells.length > 0) {
return emptyCells[Math.floor(Math.random() * emptyCells.length)];
}
}
// Advanced position evaluation for hard mode AI
function evaluateHardModePosition(cell) {
var score = 0;
var row = cell.row;
var col = cell.col;
// Base positional values with strategic weighting
if (row === 1 && col === 1) {
score += 15; // Center dominance
} else if ((row === 0 || row === 2) && (col === 0 || col === 2)) {
score += 12; // Corner control
} else {
score += 8; // Edge positions
}
// Evaluate line potential (how many lines this position affects)
var linesControlled = 0;
var lineValues = 0;
// Check row control
var rowEmpty = 0,
rowAI = 0,
rowPlayer = 0;
for (var c = 0; c < 3; c++) {
if (grid[row][c].value === 0) rowEmpty++;else if (grid[row][c].value === 2) rowAI++;else rowPlayer++;
}
if (rowPlayer === 0) {
linesControlled++;
lineValues += rowAI * 3 + rowEmpty;
}
// Check column control
var colEmpty = 0,
colAI = 0,
colPlayer = 0;
for (var r = 0; r < 3; r++) {
if (grid[r][col].value === 0) colEmpty++;else if (grid[r][col].value === 2) colAI++;else colPlayer++;
}
if (colPlayer === 0) {
linesControlled++;
lineValues += colAI * 3 + colEmpty;
}
// Check main diagonal
if (row === col) {
var diagEmpty = 0,
diagAI = 0,
diagPlayer = 0;
for (var i = 0; i < 3; i++) {
if (grid[i][i].value === 0) diagEmpty++;else if (grid[i][i].value === 2) diagAI++;else diagPlayer++;
}
if (diagPlayer === 0) {
linesControlled++;
lineValues += diagAI * 3 + diagEmpty;
}
}
// Check anti-diagonal
if (row + col === 2) {
var antiDiagEmpty = 0,
antiDiagAI = 0,
antiDiagPlayer = 0;
for (var i = 0; i < 3; i++) {
if (grid[i][2 - i].value === 0) antiDiagEmpty++;else if (grid[i][2 - i].value === 2) antiDiagAI++;else antiDiagPlayer++;
}
if (antiDiagPlayer === 0) {
linesControlled++;
lineValues += antiDiagAI * 3 + antiDiagEmpty;
}
}
score += linesControlled * 6 + lineValues * 2;
// Strategic pattern bonuses
// Opposite corner control
if (row === 0 && col === 0 && grid[2][2].value === 2 || row === 2 && col === 2 && grid[0][0].value === 2 || row === 0 && col === 2 && grid[2][0].value === 2 || row === 2 && col === 0 && grid[0][2].value === 2) {
score += 8; // Diagonal dominance
}
// Adjacent to AI pieces (connection bonus)
var adjacentAI = 0;
var checkAdj = [{
r: row - 1,
c: col
}, {
r: row + 1,
c: col
}, {
r: row,
c: col - 1
}, {
r: row,
c: col + 1
}];
for (var i = 0; i < checkAdj.length; i++) {
var adj = checkAdj[i];
if (adj.r >= 0 && adj.r < 3 && adj.c >= 0 && adj.c < 3) {
if (grid[adj.r][adj.c].value === 2) adjacentAI++;
}
}
score += adjacentAI * 4;
return score;
}
// Check for forks (moves that create two winning threats)
function checkForFork(player) {
var forkCells = [];
for (var i = 0; i < emptyCells.length; i++) {
var cell = emptyCells[i];
cell.value = player;
var winningLineCount = 0;
// Count how many winning moves this creates
for (var j = 0; j < emptyCells.length; j++) {
if (i !== j) {
var testCell = emptyCells[j];
testCell.value = player;
if (checkWinCondition(player)) {
winningLineCount++;
}
testCell.value = 0;
}
}
cell.value = 0;
if (winningLineCount >= 2) {
forkCells.push(cell);
}
}
return forkCells;
}
// Adjust strategy based on difficulty
var randomnessFactor = Math.random();
// Difficulty-based mistake chances
var strategyQuality;
if (aiDifficulty === 'easy') {
strategyQuality = 0; // No strategic moves
} else if (aiDifficulty === 'normal') {
strategyQuality = 0.6; // Medium quality strategic moves
} else {
// hard - Perfect play with zero mistakes
strategyQuality = 1.0; // Perfect strategic moves
}
// Hard mode AI - Perfect play with advanced strategy evaluation
if (aiDifficulty === 'hard') {
// Priority 1: ALWAYS win if possible (0% miss rate)
for (var i = 0; i < emptyCells.length; i++) {
var cell = emptyCells[i];
cell.value = 2;
if (checkWinCondition(2)) {
cell.value = 0;
return cell; // IMMEDIATELY take winning move - no randomness
}
cell.value = 0;
}
// Priority 2: ALWAYS block player wins (0% miss rate)
for (var i = 0; i < emptyCells.length; i++) {
var cell = emptyCells[i];
cell.value = 1;
if (checkWinCondition(1)) {
cell.value = 0;
return cell; // IMMEDIATELY block - no randomness
}
cell.value = 0;
}
// Priority 3: Create forks (multiple winning threats)
forkMoves = checkForFork(2);
if (forkMoves.length > 0) {
return forkMoves[0]; // Take any fork opportunity
}
// Priority 4: Block player forks with counter-strategy
var playerForkMoves = checkForFork(1);
if (playerForkMoves.length > 0) {
// If player can create multiple forks, create a counter-threat
if (playerForkMoves.length > 1) {
// Look for moves that force player to defend while blocking fork
for (var i = 0; i < emptyCells.length; i++) {
var cell = emptyCells[i];
cell.value = 2;
var threatsCreated = 0;
for (var j = 0; j < emptyCells.length; j++) {
if (i !== j) {
var testCell = emptyCells[j];
testCell.value = 2;
if (checkWinCondition(2)) {
threatsCreated++;
}
testCell.value = 0;
}
}
cell.value = 0;
if (threatsCreated > 0) {
return cell; // Counter-threat to force defense
}
}
}
// Otherwise block the fork
return playerForkMoves[0];
}
// Priority 5: Optimal opening strategy
if (emptyCells.length === 9) {
// First move: always take center or corner
if (grid[1][1].value === 0) {
return grid[1][1]; // Center is strongest opening
} else {
return cornerCells[0]; // Fallback to corner
}
}
if (emptyCells.length === 8) {
// Second move response
if (grid[1][1].value === 1) {
// Player took center, take any corner
return cornerCells[0];
} else {
// Player took corner or edge, take center
if (grid[1][1].value === 0) {
return grid[1][1];
}
}
}
// Priority 6: Advanced positional strategy with minimax evaluation
var bestMove = null;
var bestScore = -1000;
for (var i = 0; i < emptyCells.length; i++) {
var cell = emptyCells[i];
var score = evaluateHardModePosition(cell);
// Add advanced tactical bonuses
if (cell.row === 1 && cell.col === 1) score += 15; // Center control
if ((cell.row === 0 || cell.row === 2) && (cell.col === 0 || cell.col === 2)) score += 12; // Corner control
// Evaluate future position strength
cell.value = 2;
var futureThreats = 0;
for (var j = 0; j < emptyCells.length; j++) {
if (i !== j) {
var testCell = emptyCells[j];
testCell.value = 2;
if (checkWinCondition(2)) futureThreats++;
testCell.value = 0;
}
}
score += futureThreats * 8; // Bonus for creating future threats
cell.value = 0;
if (score > bestScore) {
bestScore = score;
bestMove = cell;
}
}
if (bestMove) {
return bestMove;
}
}
// Priority 5: Advanced tactical personalities
var moveChoices = [];
var moveScores = [];
if (aiPersonality === 0) {
// Perfect player - uses optimal strategy
if (emptyCells.length === 9) {
// First move: prefer corner
moveChoices = cornerCells.slice();
} else if (emptyCells.length === 8) {
// Second move response
if (grid[1][1].value === 1) {
// Player took center, take corner
moveChoices = cornerCells.slice();
} else {
// Player took corner or edge, take center
if (grid[1][1].value === 0) {
moveChoices.push(grid[1][1]);
}
}
} else {
// Evaluate all positions
for (var i = 0; i < emptyCells.length; i++) {
var score = evaluatePosition(emptyCells[i]);
moveScores.push({
cell: emptyCells[i],
score: score
});
}
moveScores.sort(function (a, b) {
return b.score - a.score;
});
// Take top scoring moves
var topScore = moveScores[0].score;
for (var i = 0; i < moveScores.length; i++) {
if (moveScores[i].score >= topScore - 1) {
moveChoices.push(moveScores[i].cell);
}
}
}
} else if (aiPersonality === 1) {
// Trap setter - tries to create winning patterns
if (grid[1][1].value === 0) {
moveChoices.push(grid[1][1]);
moveChoices.push(grid[1][1]); // Double weight
}
// Look for L-shaped patterns
if (grid[0][0].value === 2 && grid[2][2].value === 0) {
moveChoices.push(grid[2][2]);
}
if (grid[0][2].value === 2 && grid[2][0].value === 0) {
moveChoices.push(grid[2][0]);
}
// Add corners for trap potential
if (cornerCells.length > 0) {
moveChoices = moveChoices.concat(cornerCells);
}
} else if (aiPersonality === 2) {
// Defensive player - blocks and controls center
if (grid[1][1].value === 0) {
moveChoices.push(grid[1][1]);
moveChoices.push(grid[1][1]);
moveChoices.push(grid[1][1]); // Triple weight for center
}
// Prefer moves that block multiple lines
for (var i = 0; i < emptyCells.length; i++) {
var blockCount = countWinningLines(emptyCells[i].row, emptyCells[i].col, 1);
if (blockCount >= 2) {
moveChoices.push(emptyCells[i]);
}
}
if (moveChoices.length === 0 && cornerCells.length > 0) {
moveChoices = cornerCells.slice();
}
} else if (aiPersonality === 3) {
// Mirror player - plays symmetrically
var playerMoves = [];
for (var r = 0; r < 3; r++) {
for (var c = 0; c < 3; c++) {
if (grid[r][c].value === 1) {
playerMoves.push({
row: r,
col: c
});
}
}
}
if (playerMoves.length > 0) {
var lastMove = playerMoves[playerMoves.length - 1];
// Try to mirror across center
var mirrorRow = 2 - lastMove.row;
var mirrorCol = 2 - lastMove.col;
if (grid[mirrorRow][mirrorCol].value === 0) {
moveChoices.push(grid[mirrorRow][mirrorCol]);
moveChoices.push(grid[mirrorRow][mirrorCol]); // Double weight
}
}
// Add strategic positions
if (grid[1][1].value === 0) {
moveChoices.push(grid[1][1]);
}
if (cornerCells.length > 0) {
moveChoices.push(cornerCells[Math.floor(Math.random() * cornerCells.length)]);
}
} else if (aiPersonality === 4) {
// Edge control player - unusual but effective
if (edgeCells.length > 0) {
// Prefer edges that connect to existing pieces
for (var i = 0; i < edgeCells.length; i++) {
var edge = edgeCells[i];
var adjacentAI = 0;
// Check adjacent cells
var checkPositions = [{
r: edge.row - 1,
c: edge.col
}, {
r: edge.row + 1,
c: edge.col
}, {
r: edge.row,
c: edge.col - 1
}, {
r: edge.row,
c: edge.col + 1
}];
for (var j = 0; j < checkPositions.length; j++) {
var pos = checkPositions[j];
if (pos.r >= 0 && pos.r < 3 && pos.c >= 0 && pos.c < 3) {
if (grid[pos.r][pos.c].value === 2) {
adjacentAI++;
}
}
}
if (adjacentAI > 0) {
moveChoices.push(edge);
moveChoices.push(edge); // Double weight for connected edges
}
}
if (moveChoices.length === 0) {
moveChoices = edgeCells.slice();
}
}
// Sometimes take center
if (Math.random() < 0.3 && grid[1][1].value === 0) {
moveChoices.push(grid[1][1]);
}
} else if (aiPersonality === 5) {
// Chaos player - creates complex board states
var complexityScore = [];
for (var i = 0; i < emptyCells.length; i++) {
var cell = emptyCells[i];
// Calculate how many lines this move affects
var linesAffected = 0;
if (true) linesAffected++; // Row
if (true) linesAffected++; // Column
if (cell.row === cell.col || cell.row + cell.col === 2) {
linesAffected++; // Diagonal
}
complexityScore.push({
cell: cell,
complexity: linesAffected
});
}
// Prefer high complexity moves
complexityScore.sort(function (a, b) {
return b.complexity - a.complexity;
});
for (var i = 0; i < Math.min(3, complexityScore.length); i++) {
moveChoices.push(complexityScore[i].cell);
}
} else if (aiPersonality === 6) {
// Pattern player - follows specific winning patterns
var patterns = [
// Corner-opposite-corner
[{
r: 0,
c: 0
}, {
r: 2,
c: 2
}], [{
r: 0,
c: 2
}, {
r: 2,
c: 0
}],
// L-shapes
[{
r: 0,
c: 0
}, {
r: 0,
c: 2
}], [{
r: 0,
c: 0
}, {
r: 2,
c: 0
}], [{
r: 2,
c: 2
}, {
r: 2,
c: 0
}], [{
r: 2,
c: 2
}, {
r: 0,
c: 2
}]];
for (var p = 0; p < patterns.length; p++) {
var pattern = patterns[p];
var hasFirst = grid[pattern[0].r][pattern[0].c].value === 2;
var secondEmpty = grid[pattern[1].r][pattern[1].c].value === 0;
if (hasFirst && secondEmpty) {
moveChoices.push(grid[pattern[1].r][pattern[1].c]);
moveChoices.push(grid[pattern[1].r][pattern[1].c]); // Double weight
}
}
// Default to smart positions
if (moveChoices.length === 0) {
if (grid[1][1].value === 0) {
moveChoices.push(grid[1][1]);
}
if (cornerCells.length > 0) {
moveChoices = moveChoices.concat(cornerCells);
}
}
} else {
// Adaptive player - changes strategy based on game state
var gamePhase = 9 - emptyCells.length; // 0-8, higher = later
if (gamePhase <= 2) {
// Early game: control key positions
if (grid[1][1].value === 0) {
moveChoices.push(grid[1][1]);
moveChoices.push(grid[1][1]);
}
if (cornerCells.length > 0) {
moveChoices = moveChoices.concat(cornerCells);
}
} else if (gamePhase <= 5) {
// Mid game: create threats
for (var i = 0; i < emptyCells.length; i++) {
var threatLevel = countWinningLines(emptyCells[i].row, emptyCells[i].col, 2);
if (threatLevel >= 1) {
moveChoices.push(emptyCells[i]);
if (threatLevel >= 2) {
moveChoices.push(emptyCells[i]); // Extra weight for multi-threats
}
}
}
} else {
// Late game: optimize winning chances
for (var i = 0; i < emptyCells.length; i++) {
moveChoices.push(emptyCells[i]);
}
}
}
// Add calculated randomness
if (Math.random() < 0.1) {
// 10% chance to add unexpected move
if (validCells.length > 0) {
var randomCell = validCells[Math.floor(Math.random() * validCells.length)];
moveChoices.push(randomCell);
}
}
// If we have strategic choices, pick from them
if (moveChoices.length > 0) {
// Sometimes pick the most frequent choice (if duplicates exist)
var choiceFrequency = {};
for (var i = 0; i < moveChoices.length; i++) {
var key = moveChoices[i].row + ',' + moveChoices[i].col;
choiceFrequency[key] = (choiceFrequency[key] || 0) + 1;
}
// Create weighted selection
var weightedChoices = [];
for (var i = 0; i < moveChoices.length; i++) {
weightedChoices.push(moveChoices[i]);
}
return weightedChoices[Math.floor(Math.random() * weightedChoices.length)];
}
// Easy mode already handled above with helpful logic
// Final fallback: intelligent selection
var fallbackChoices = [];
// Prioritize based on position value (less strategic in easy mode)
if (aiDifficulty !== 'easy' || Math.random() < 0.5) {
if (grid[1][1].value === 0) {
fallbackChoices.push(grid[1][1]);
}
}
if (cornerCells.length > 0 && (aiDifficulty !== 'easy' || Math.random() < 0.6)) {
fallbackChoices = fallbackChoices.concat(cornerCells);
}
if (edgeCells.length > 0 && (aiDifficulty === 'easy' || Math.random() < 0.3)) {
fallbackChoices.push(edgeCells[Math.floor(Math.random() * edgeCells.length)]);
}
if (fallbackChoices.length === 0) {
fallbackChoices = validCells;
}
if (fallbackChoices.length > 0) {
return fallbackChoices[Math.floor(Math.random() * fallbackChoices.length)];
}
// Ultimate fallback: return first empty cell found
for (var row = 0; row < 3; row++) {
for (var col = 0; col < 3; col++) {
if (grid[row][col].value === 0 && !grid[row][col].marker) {
return grid[row][col];
}
}
}
// If still no valid move found, return any empty cell regardless of marker status
for (var row = 0; row < 3; row++) {
for (var col = 0; col < 3; col++) {
if (grid[row][col].value === 0) {
return grid[row][col];
}
}
}
return null;
}
function checkWinCondition(player) {
// Check rows
for (var row = 0; row < 3; row++) {
if (grid[row][0].value === player && grid[row][1].value === player && grid[row][2].value === player) {
return true;
}
}
// Check columns
for (var col = 0; col < 3; col++) {
if (grid[0][col].value === player && grid[1][col].value === player && grid[2][col].value === player) {
return true;
}
}
// Check diagonals
if (grid[0][0].value === player && grid[1][1].value === player && grid[2][2].value === player) {
return true;
}
if (grid[0][2].value === player && grid[1][1].value === player && grid[2][0].value === player) {
return true;
}
return false;
}
function resetGame() {
gameOver = false;
// Immediately clear AI processing to prevent stuck states
aiProcessing = false;
// Clear any pending AI timeouts
LK.clearTimeout(); // Clear any pending timeouts
// Stop all active tweens to prevent conflicts
// Stop tweens on UI elements
tween.stop(playAgainBg);
tween.stop(playAgainBtn);
tween.stop(statusText);
// Stop tweens on difficulty blocks
tween.stop(easyBlock);
tween.stop(normalBlock);
tween.stop(hardBlock);
// Stop tweens on confirmation dialog elements
tween.stop(confirmationBg);
tween.stop(confirmationText);
tween.stop(yesBtn);
tween.stop(noBtn);
// Stop tweens on all cell markers
for (var row = 0; row < 3; row++) {
for (var col = 0; col < 3; col++) {
var cell = grid[row][col];
if (cell.marker) {
tween.stop(cell.marker);
}
}
}
// Force clear any stuck AI state
if (isAIMode && currentPlayer === 2) {
currentPlayer = 1; // Reset to player's turn
}
// Start according to game mode
if (gameMode === 'ai') {
currentPlayer = 1; // Player always starts in AI mode
isAIMode = true;
} else if (gameMode === 'twoPlayer') {
currentPlayer = Math.random() < 0.5 ? 1 : 2;
isAIMode = false;
} else {
// Menu mode
currentPlayer = 1;
isAIMode = false;
}
// Clear grid
for (var row = 0; row < 3; row++) {
for (var col = 0; col < 3; col++) {
var cell = grid[row][col];
cell.value = 0;
if (cell.marker) {
// Stop any active tweens on marker before destroying
tween.stop(cell.marker);
// Reset marker properties to prevent visual glitches
cell.marker.alpha = 0;
cell.marker.scaleX = 1;
cell.marker.scaleY = 1;
cell.marker.tint = 0xffffff;
cell.marker.rotation = 0;
// Remove from parent before destroying
if (cell.marker.parent) {
cell.marker.parent.removeChild(cell.marker);
}
cell.marker.destroy();
cell.marker = null;
}
// Clean up second marker for Tom ve Jerry style
if (cell.marker2) {
// Stop any active tweens on second marker before destroying
tween.stop(cell.marker2);
// Reset marker properties to prevent visual glitches
cell.marker2.alpha = 0;
cell.marker2.scaleX = 1;
cell.marker2.scaleY = 1;
cell.marker2.tint = 0xffffff;
cell.marker2.rotation = 0;
// Remove from parent before destroying
if (cell.marker2.parent) {
cell.marker2.parent.removeChild(cell.marker2);
}
cell.marker2.destroy();
cell.marker2 = null;
}
}
}
// Clear UI
statusText.setText('');
statusText.alpha = 0;
playAgainBtn.alpha = 0;
playAgainBg.alpha = 0;
// Stop any pulsing animation on play again button
tween.stop(playAgainBg);
tween.stop(playAgainBtn);
playAgainBg.scaleX = 1;
playAgainBg.scaleY = 1;
playAgainBtn.interactive = false;
// Hide all settings and package UI elements
changeAppearanceBtn.alpha = 0;
changeAppearanceBtn.interactive = false;
// Hide current style text
currentStyleText.alpha = 0;
packageTitle.alpha = 0;
package1Btn.alpha = 0;
package2Btn.alpha = 0;
package3Btn.alpha = 0;
package4Btn.alpha = 0;
package5Btn.alpha = 0;
package6Btn.alpha = 0;
package7Btn.alpha = 0;
package1Bg.alpha = 0;
package2Bg.alpha = 0;
package3Bg.alpha = 0;
package4Bg.alpha = 0;
package5Bg.alpha = 0;
package6Bg.alpha = 0;
package7Bg.alpha = 0;
// Disable package button interactions
package1Btn.interactive = false;
package2Btn.interactive = false;
package3Btn.interactive = false;
package4Btn.interactive = false;
package5Btn.interactive = false;
package6Btn.interactive = false;
package7Btn.interactive = false;
// Remove win line
if (winLine) {
// Stop any active tweens on win line to prevent memory leaks
tween.stop(winLine.line);
tween.stop(winLine); // Stop any tweens on the container too
// Reset line properties before destroying
winLine.line.alpha = 0;
winLine.line.scaleX = 0;
winLine.line.tint = 0xffffff; // Reset tint
// Remove from parent before destroying
if (winLine.parent) {
winLine.parent.removeChild(winLine);
}
winLine.destroy();
winLine = null;
}
updateTurnDisplay();
}
// Play again button handler
playAgainBtn.down = function (x, y, obj) {
if (gameOver) {
resetGame();
}
};
// Add small delay to prevent initial freeze when entering game
var gameReady = false;
LK.setTimeout(function () {
gameReady = true;
}, 50); // Reduced delay for better responsiveness
Tom ve Jerry kısmından Tom'un yuvarlak kafasını oluştur. In-Game asset. High contrast. No shadows
Tom ve Jerry çizgi filminden jerry'nin kafasını oluştur. In-Game asset. High contrast. No shadows
Süper kahraman olan Batman'ın kafasını oluştur. In-Game asset. High contrast. No shadows
Süper kötü olan joker'in kafasını oluştur. In-Game asset. High contrast. No shadows