User prompt
Please fix the bug: 'TypeError: game.clearAllHighlights is not a function' in or related to this line: 'game.clearAllHighlights();' Line Number: 2061
Code edit (1 edits merged)
Please save this source code
User prompt
fix the error
Code edit (5 edits merged)
Please save this source code
User prompt
Please fix the bug: 'unit is not defined' in or related to this line: 'tween(button, {' Line Number: 753 ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Please fix the bug: 'unit is not defined' in or related to this line: 'tween(button, {' Line Number: 753
Code edit (3 edits merged)
Please save this source code
User prompt
now when the player clicks the player vs player button, it should start the match but the ai shouldnt controll any characters, its two players playing at turn
Code edit (5 edits merged)
Please save this source code
User prompt
now create two more ai play pattern, the current one can be for easy mode, create harder ones for medium and hard
User prompt
When the player clicks the player vs ai button it should pop up a small window asking for which difficulty, easy medium or hard, if the player clicks outside that window it closes
Code edit (1 edits merged)
Please save this source code
User prompt
Keep the game logo during the select mode screen
User prompt
make the player vs player button wider in x, and the back button slimmer in x
User prompt
Add an game mode screen, when the player presses the play game button it goes to the game mode screen where it has two buttons, one saying player vs AI and the other Player vs Player, for now neither button does anything next
Code edit (2 edits merged)
Please save this source code
User prompt
solve the issue of characters occupying same position, no character can occupy an currently occupied position, enemies characters are doing that
User prompt
king, knights and mage can jump over characters, move to front of them if is within movement range and its not an occupied position
User prompt
enemy characters are overlapping ocuppied positions, solve that
User prompt
Please fix the bug: 'ReferenceError: Knight is not defined' in or related to this line: 'unit = new Knight().init(type, team, row, col);' Line Number: 735
Code edit (1 edits merged)
Please save this source code
User prompt
Fix 4: Fix endTurn function to prevent skipping AI turn by checking state transitions properly
User prompt
Fix 3: Improve AI wizard strategy to fix adjacent cell access for area attacks
User prompt
Fix 2: Properly initialize AI in game code with game reference to fix AI turns being skipped
User prompt
Fix 1: Improve AIPlayer class by properly passing game reference to avoid method access issues
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var AIPlayer = Container.expand(function () { var self = Container.call(this); self.game = null; self.makeMove = function () { if (game.gameState !== 'aiTurn') return false; var difficultyLevel = 1.0; var units = game.getTeamUnits('red'); if (difficultyLevel < 0.3 && Math.random() < 0.7) { var movableUnits = units.filter(function (u) { return u.getPossibleMoves(game.grid).length > 0; }); if (movableUnits.length > 0) { var randomUnit = movableUnits[Math.floor(Math.random() * movableUnits.length)]; var possibleMoves = randomUnit.getPossibleMoves(game.grid); var randomMove = possibleMoves[Math.floor(Math.random() * possibleMoves.length)]; game.selectUnit(randomUnit); game.moveSelectedUnit(randomMove.row, randomMove.col); return true; } } for (var i = 0; i < units.length; i++) { var unit = units[i]; var attacks = unit.getPossibleAttacks(game.grid); if (attacks.length > 0) { var kingAttack = attacks.find(function (a) { return game.grid[a.row][a.col].occupiedBy && game.grid[a.row][a.col].occupiedBy.isKing; }); if (kingAttack) { game.selectUnit(unit); game.attackCell(game.grid[kingAttack.row][kingAttack.col]); return true; } var criticalAttack = attacks.find(function (a) { var target = game.grid[a.row][a.col].occupiedBy; return target && game.isCriticalDamage(unit.type, target.type); }); if (criticalAttack) { game.selectUnit(unit); game.attackCell(game.grid[criticalAttack.row][criticalAttack.col]); return true; } if (unit.type === 'warrior' && attacks.length > 0) { game.selectUnit(unit); game.attackCell(game.grid[attacks[0].row][attacks[0].col]); return true; } if (unit.type === 'wizard' && attacks.length > 0) { var bestAttack = attacks[0], bestCount = 0; for (var j = 0; j < attacks.length; j++) { var attack = attacks[j]; var adjacentCells = self.game.getAdjacentCells(attack.row, attack.col); var enemyCount = 0; for (var k = 0; k < adjacentCells.length; k++) { var cell = adjacentCells[k]; if (cell.occupied && cell.occupiedBy.team === 'blue') enemyCount++; } if (enemyCount > bestCount) { bestCount = enemyCount; bestAttack = attack; } } game.selectUnit(unit); game.attackCell(game.grid[bestAttack.row][bestAttack.col]); return true; } game.selectUnit(unit); game.attackCell(game.grid[attacks[0].row][attacks[0].col]); return true; } } var playerKing = game.getKing('blue'); if (playerKing) { var closestUnit = null, closestDistance = Infinity; for (var i = 0; i < units.length; i++) { var unit = units[i]; var moves = unit.getPossibleMoves(game.grid); if (moves.length > 0) { var dist = Math.abs(unit.row - playerKing.row) + Math.abs(unit.col - playerKing.col); if (unit.type === 'knight') dist -= 2;else if (unit.type === 'archer') { if (dist > 4) dist -= 1;else if (dist < 3) dist += 2; } else if (unit.type === 'warrior') dist -= 3;else if (unit.type === 'wizard') { if (dist > 3 && dist < 6) dist -= 2; } if (dist < closestDistance) { closestUnit = unit; closestDistance = dist; } } } if (closestUnit) { var bestMove = null, bestMoveScore = -Infinity; var moves = closestUnit.getPossibleMoves(game.grid); for (var i = 0; i < moves.length; i++) { var move = moves[i]; var moveScore = closestDistance - (Math.abs(move.row - playerKing.row) + Math.abs(move.col - playerKing.col)); var difficultyLevel = 1.0; if (closestUnit.type === 'knight') { var potentialAttackRange = Math.abs(move.row - playerKing.row) + Math.abs(move.col - playerKing.col); if (potentialAttackRange <= closestUnit.attackRange + 1) moveScore += 3 * difficultyLevel; } else if (closestUnit.type === 'archer') { var distAfterMove = Math.abs(move.row - playerKing.row) + Math.abs(move.col - playerKing.col); if (distAfterMove >= 3 && distAfterMove <= 5) moveScore += 4 * difficultyLevel; } else if (closestUnit.type === 'wizard') { var adjacentCells = self.game.getAdjacentCells(move.row, move.col); var playerUnitsNearby = 0; for (var j = 0; j < adjacentCells.length; j++) { var cell = adjacentCells[j]; if (cell.occupied && cell.occupiedBy.team === 'blue') playerUnitsNearby++; } moveScore += playerUnitsNearby * 2; } if (moveScore > bestMoveScore) { bestMove = move; bestMoveScore = moveScore; } } if (bestMove) { game.selectUnit(closestUnit); game.moveSelectedUnit(bestMove.row, bestMove.col); return true; } } } var unitsInDanger = units.filter(function (unit) { var playerUnits = game.getTeamUnits('blue'); for (var i = 0; i < playerUnits.length; i++) { var playerUnit = playerUnits[i]; var rowDiff = Math.abs(playerUnit.row - unit.row); var colDiff = Math.abs(playerUnit.col - unit.col); var inDanger = false; if (playerUnit.type === 'warrior' && rowDiff + colDiff <= playerUnit.moveRange + playerUnit.attackRange) inDanger = true;else if (playerUnit.type === 'archer' && colDiff === 0 && rowDiff <= playerUnit.attackRange + 1) inDanger = true;else if (playerUnit.type === 'knight' && (rowDiff === 0 || colDiff === 0) && rowDiff + colDiff <= playerUnit.attackRange + 1) inDanger = true;else if (playerUnit.type === 'wizard' && rowDiff + colDiff <= playerUnit.moveRange + 2) inDanger = true; if (inDanger && unit.isKing) return true;else if (inDanger && unit.health < 50) return true; } return false; }); if (unitsInDanger.length > 0) { var unitToSave = unitsInDanger.find(function (u) { return u.isKing; }) || unitsInDanger[0]; var moves = unitToSave.getPossibleMoves(game.grid); if (moves.length > 0) { var playerUnits = game.getTeamUnits('blue'); var bestMove = null, bestSafetyScore = -Infinity; for (var i = 0; i < moves.length; i++) { var move = moves[i], safetyScore = 0; for (var j = 0; j < playerUnits.length; j++) { var playerUnit = playerUnits[j]; var dist = Math.abs(move.row - playerUnit.row) + Math.abs(move.col - playerUnit.col); safetyScore += dist; } if (safetyScore > bestSafetyScore) { bestSafetyScore = safetyScore; bestMove = move; } } if (bestMove) { game.selectUnit(unitToSave); game.moveSelectedUnit(bestMove.row, bestMove.col); return true; } } } var movableUnits = units.filter(function (u) { return u.getPossibleMoves(game.grid).length > 0; }); if (movableUnits.length > 0) { var randomUnit = movableUnits[Math.floor(Math.random() * movableUnits.length)]; var possibleMoves = randomUnit.getPossibleMoves(game.grid); var randomMove = possibleMoves[Math.floor(Math.random() * possibleMoves.length)]; game.selectUnit(randomUnit); game.moveSelectedUnit(randomMove.row, randomMove.col); return true; } return false; }; return self; }); var CriticalDamageEffect = Container.expand(function () { var self = Container.call(this); self.init = function (damage, x, y) { var critText = new Text2('CRITICAL HIT!', { size: 80, fill: '#FF0000' }); critText.anchor.set(0.5, 0.5); self.addChild(critText); var damageText = new Text2('-' + damage, { size: 100, fill: '#FFFF00' }); damageText.anchor.set(0.5, 0.5); damageText.y = 80; self.addChild(damageText); self.x = x; self.y = y; self.scale.set(0.1); self.alpha = 0; tween(self, { scaleX: 1.2, scaleY: 1.2, alpha: 1 }, { duration: 300, easing: tween.elasticOut }); LK.setTimeout(function () { tween(self, { scaleX: 1.5, scaleY: 1.5, alpha: 0, y: self.y - 100 }, { duration: 700, easing: tween.easeOutQuad, onFinish: function onFinish() { self.parent.removeChild(self); } }); }, 1200); return self; }; return self; }); var GridCell = Container.expand(function () { var self = Container.call(this); self.row = 0; self.col = 0; self.occupied = false; self.occupiedBy = null; self.highlighted = false; self.highlightType = null; var cellGraphic = self.attachAsset('grid_cell', { anchorX: 0.5, anchorY: 0.5, alpha: 0.5 }); self.highlight = function (type) { if (self.highlightAsset) self.removeChild(self.highlightAsset); self.highlighted = true; self.highlightType = type; var asset = null; if (type === 'move') asset = 'highlight_move';else if (type === 'attack') asset = 'highlight_attack';else if (type === 'selected') asset = 'highlight_selected'; if (asset) { self.highlightAsset = self.attachAsset(asset, { anchorX: 0.5, anchorY: 0.5, alpha: 0.5 }); } }; self.clearHighlight = function () { if (self.highlightAsset) { self.removeChild(self.highlightAsset); self.highlightAsset = null; } self.highlighted = false; self.highlightType = null; }; self.down = function () { if (game.gameState === 'playerTurn') game.handleCellClick(self); }; return self; }); var SettingsScreen = Container.expand(function () { var self = Container.call(this); var titleText = new Text2('SETTINGS', { size: 150, fill: '#FFFFFF' }); titleText.anchor.set(0.5, 0); titleText.y = -2732 / 3; self.addChild(titleText); var createToggle = function createToggle(text, yPos, initialState, xPos) { var container = new Container(); container.y = yPos; container.x = xPos; var label = new Text2(text, { size: 80, fill: '#FFFFFF' }); label.anchor.set(0, 0.5); container.addChild(label); var toggleBg = LK.getAsset('grid_cell_dark', { anchorX: 0.5, anchorY: 0.5, width: 200, height: 100, alpha: 0.8 }); toggleBg.x = 900; container.addChild(toggleBg); var indicator = LK.getAsset('grid_cell', { anchorX: 0.5, anchorY: 0.5, width: 80, height: 80 }); indicator.x = initialState ? 950 : 850; indicator.y = 0; container.addChild(indicator); container.state = initialState; toggleBg.down = function () { container.state = !container.state; tween(indicator, { x: container.state ? 950 : 850 }, { duration: 200, easing: tween.easeOutQuad }); }; return container; }; var musicToggle = createToggle('Music', 550, true, -500); self.addChild(musicToggle); var backButton = new Container(); var backBg = LK.getAsset('grid_cell', { anchorX: 0.5, anchorY: 0.5, alpha: 0.8, width: 500, height: 120 }); var backText = new Text2('BACK', { size: 80, fill: '#000000' }); backText.anchor.set(0.5, 0.5); backButton.addChild(backBg); backButton.addChild(backText); backButton.x = 0; backButton.y = musicToggle.y + 200; self.addChild(backButton); backButton.down = function () { tween(backBg, { scaleX: 0.95, scaleY: 0.95 }, { duration: 100, easing: tween.easeOutQuad }); }; function animateBackButton() { tween(backBg, { scaleX: 1.1, scaleY: 1.1 }, { duration: 800, easing: tween.easeInOut, onFinish: function onFinish() { tween(backBg, { scaleX: 1.0, scaleY: 1.0 }, { duration: 800, easing: tween.easeInOut, onFinish: animateBackButton }); } }); } animateBackButton(); backButton.up = function () { tween(backBg, { scaleX: 1, scaleY: 1 }, { duration: 200, easing: tween.elasticOut, onFinish: function onFinish() { game.showTitleScreen(); } }); }; return self; }); var TitleScreen = Container.expand(function () { var self = Container.call(this); var logo = LK.getAsset('game_logo', { anchorX: 0.5, anchorY: 0.5, x: 0, y: -200 }); self.addChild(logo); var titleText = new Text2('', { size: 200, fill: '#FFFFFF' }); self.addChild(titleText); function createButton(text, yOffset) { var button = new Container(); var bg = LK.getAsset('grid_cell', { anchorX: 0.5, anchorY: 0.5, alpha: 0.8, width: 800, height: 150 }); button.addChild(bg); var buttonText = new Text2(text, { size: 100, fill: '#000000' }); buttonText.anchor.set(0.5, 0.5); button.addChild(buttonText); button.y = yOffset; button.down = function () { tween(bg, { scaleX: 0.95, scaleY: 0.95 }, { duration: 100, easing: tween.easeOutQuad }); }; button.up = function () { tween(bg, { scaleX: 1, scaleY: 1 }, { duration: 200, easing: tween.elasticOut }); }; return button; } var playButton = createButton('PLAY GAME', 100); var tutorialButton = createButton('TUTORIAL', 300); var settingsButton = createButton('SETTINGS', 500); self.addChild(playButton); self.addChild(tutorialButton); self.addChild(settingsButton); function animateButton(button, delay) { LK.setTimeout(function () { tween(button, { scaleX: 1.1, scaleY: 1.1 }, { duration: 800, easing: tween.easeInOut, onFinish: function onFinish() { tween(button, { scaleX: 1.0, scaleY: 1.0 }, { duration: 800, easing: tween.easeInOut, onFinish: function onFinish() { animateButton(button, 0); } }); } }); }, delay); } animateButton(playButton, 0); animateButton(tutorialButton, 300); animateButton(settingsButton, 600); playButton.down = function () { tween(playButton.children[0], { scaleX: 0.95, scaleY: 0.95 }, { duration: 100, easing: tween.easeOutQuad }); }; playButton.up = function () { tween(playButton.children[0], { scaleX: 1, scaleY: 1 }, { duration: 200, easing: tween.elasticOut, onFinish: function onFinish() { game.startGame(); } }); }; tutorialButton.down = function () { tween(tutorialButton.children[0], { scaleX: 0.95, scaleY: 0.95 }, { duration: 100, easing: tween.easeOutQuad }); }; tutorialButton.up = function () { tween(tutorialButton.children[0], { scaleX: 1, scaleY: 1 }, { duration: 200, easing: tween.elasticOut, onFinish: function onFinish() { game.showTutorial(); } }); }; settingsButton.down = function () { tween(settingsButton.children[0], { scaleX: 0.95, scaleY: 0.95 }, { duration: 100, easing: tween.easeOutQuad }); }; settingsButton.up = function () { tween(settingsButton.children[0], { scaleX: 1, scaleY: 1 }, { duration: 200, easing: tween.elasticOut, onFinish: function onFinish() { game.showSettings(); } }); }; return self; }); // Vector2 class var Vector2 = Container.expand(function () { var self = Container.call(this); self.init = function (x, y) { self.x = x || 0; self.y = y || 0; return self; }; self.add = function (v) { return new Vector2().init(self.x + v.x, self.y + v.y); }; self.subtract = function (v) { return new Vector2().init(self.x - v.x, self.y - v.y); }; self.multiply = function (scalar) { return new Vector2().init(self.x * scalar, self.y * scalar); }; self.clone = function () { return new Vector2().init(self.x, self.y); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ var tutorialOffset = new Vector2().init(0, 0); var dragNode = null; var GRID_ROWS = 10; var GRID_COLS = 5; var CELL_SIZE = 250; var GRID_PADDING_X = (2048 - GRID_COLS * CELL_SIZE) / 2; var GRID_PADDING_Y = (2732 - GRID_ROWS * CELL_SIZE) / 2; var grid = []; var units = []; var selectedUnit = null; var gameState = 'mainMenu'; var ai = new AIPlayer(); ai.game = game; var statusText = new Text2('Player Turn', { size: 120, fill: 0xFFFFFF }); var titleScreen = new TitleScreen(); var tutorialScreen = new Container(); // Placeholder, implement as needed var settingsScreen = new SettingsScreen(); game.settingsScreen = settingsScreen; game.move = function (x, y, obj) { if (dragNode) { dragNode.x = x; dragNode.y = y; } }; function handleMove(x, y, obj) { if (dragNode) { dragNode.x = x; dragNode.y = y; } } game.down = function (x, y, obj) { if (typeof character !== 'undefined') { dragNode = character; } else { dragNode = null; } if (obj && obj.down) obj.__isTouchDown = true; if (handleMove) handleMove(x, y, obj); }; game.up = function (x, y, obj) { dragNode = null; }; titleScreen.x = 1024; titleScreen.y = 1366; tutorialScreen.x = 0; tutorialScreen.y = 0; settingsScreen.x = 1024; settingsScreen.y = 1366; function initializeGame() { for (var row = 0; row < GRID_ROWS; row++) { grid[row] = []; for (var col = 0; col < GRID_COLS; col++) { grid[row][col] = {}; } } var background = LK.getAsset('background', { anchorX: 0, anchorY: 0, x: 0, y: 0, width: 2048, height: 2732 }); game.addChild(background); game.showTitleScreen(); } function createUnits() { createUnit('knight', 'blue', 8, 0); createUnit('warrior', 'blue', 8, 1); createUnit('warrior', 'blue', 8, 2); createUnit('warrior', 'blue', 8, 3); createUnit('knight', 'blue', 8, 4); createUnit('archer', 'blue', 9, 0); createUnit('wizard', 'blue', 9, 1); createUnit('king', 'blue', 9, 2); createUnit('wizard', 'blue', 9, 3); createUnit('archer', 'blue', 9, 4); createUnit('knight', 'red', 1, 0); createUnit('warrior', 'red', 1, 1); createUnit('warrior', 'red', 1, 2); createUnit('warrior', 'red', 1, 3); createUnit('knight', 'red', 1, 4); createUnit('archer', 'red', 0, 0); createUnit('wizard', 'red', 0, 1); createUnit('king', 'red', 0, 2); createUnit('wizard', 'red', 0, 3); createUnit('archer', 'red', 0, 4); } function createUnit(type, team, row, col) { var unit; switch (type) { case 'king': unit = new King().init(type, team, row, col); break; case 'knight': unit = new Knight().init(type, team, row, col); break; case 'archer': unit = new Archer().init(type, team, row, col); break; case 'wizard': unit = new Wizard().init(type, team, row, col); break; case 'warrior': unit = new Warrior().init(type, team, row, col); break; } unit.x = grid[row][col].x; unit.y = grid[row][col].y; unit.unitGraphic.alpha = 0.8; unit.healthText = new Text2(unit.health.toString(), { size: 50, fill: 0xFFD700 }); unit.healthText.anchor.set(0.5, 0.5); unit.healthText.y = unit.unitGraphic.height / 2 + 10; unit.addChild(unit.healthText); unit.unitGraphic.scale.set(0.1); unit.unitGraphic.alpha = 0.3; game.addChild(unit); units.push(unit); grid[row][col].occupied = true; grid[row][col].occupiedBy = unit; if (team === 'blue') { unit.down = function (x, y, obj) { if (game.gameState === 'playerTurn') selectUnit(unit); }; } tween(unit.unitGraphic, { scaleX: 1.0, scaleY: 1.0, alpha: 0.8 }, { duration: 600, easing: tween.elasticOut, delay: 100 * (row + col) % 5 }); return unit; } game.handleCellClick = function (cell) { if (!selectedUnit || game.gameState !== 'playerTurn') return; if (cell.highlighted && cell.highlightType === 'move') moveSelectedUnit(cell.row, cell.col);else if (cell.highlighted && cell.highlightType === 'attack') attackCell(cell); }; function selectUnit(unit) { if (unit.team !== 'blue' && gameState === 'playerTurn') return; if (unit.team !== 'red' && gameState === 'aiTurn') return; if (selectedUnit) { selectedUnit.deselect(); clearAllHighlights(); } selectedUnit = unit; selectedUnit.select(); tween(selectedUnit.unitGraphic, { scaleX: 1.2, scaleY: 1.2, alpha: 1.0 }, { duration: 200, easing: tween.elasticOut, onFinish: function onFinish() { tween(selectedUnit.unitGraphic, { scaleX: 1.0, scaleY: 1.0 }, { duration: 200, easing: tween.elasticOut }); } }); grid[unit.row][unit.col].highlight('selected'); var possibleMoves = unit.getPossibleMoves(grid); for (var i = 0; i < possibleMoves.length; i++) { (function (index) { LK.setTimeout(function () { if (selectedUnit === unit) { var move = possibleMoves[index]; grid[move.row][move.col].highlight('move'); } }, index * 30); })(i); } var possibleAttacks = unit.getPossibleAttacks(grid); for (var i = 0; i < possibleAttacks.length; i++) { (function (index) { LK.setTimeout(function () { if (selectedUnit === unit) { var attack = possibleAttacks[index]; grid[attack.row][attack.col].highlight('attack'); } }, (possibleMoves.length + index) * 30); })(i); } } function moveSelectedUnit(targetRow, targetCol) { if (!selectedUnit) return; grid[selectedUnit.row][selectedUnit.col].occupied = false; grid[selectedUnit.row][selectedUnit.col].occupiedBy = null; selectedUnit.moveTo(targetRow, targetCol); var targetX = grid[targetRow][targetCol].x; var targetY = grid[targetRow][targetCol].y; tween(selectedUnit, { x: targetX, y: targetY }, { duration: 300, easing: tween.easeOutQuad, onFinish: function onFinish() { grid[targetRow][targetCol].occupied = true; grid[targetRow][targetCol].occupiedBy = selectedUnit; selectedUnit.deselect(); clearAllHighlights(); selectedUnit = null; checkForAutoAttack(); endTurn(); } }); } function attackCell(cell) { if (!selectedUnit || !cell.occupied || cell.occupiedBy.team === selectedUnit.team) return; var targetUnit = cell.occupiedBy; var originalX = selectedUnit.x, originalY = selectedUnit.y; var directionX = targetUnit.x - selectedUnit.x, directionY = targetUnit.y - selectedUnit.y; var distance = Math.sqrt(directionX * directionX + directionY * directionY); var normalizedX = directionX / distance * 30, normalizedY = directionY / distance * 30; tween(selectedUnit, { x: selectedUnit.x + normalizedX * 1.5, y: selectedUnit.y + normalizedY * 1.5 }, { duration: 200, easing: tween.easeOutQuad, onFinish: function onFinish() { LK.effects.flashObject(targetUnit, 0xff0000, 400); tween(selectedUnit, { x: originalX, y: originalY }, { duration: 200, easing: tween.easeOutQuad, onFinish: function onFinish() { var isCritical = isCriticalDamage(selectedUnit.type, targetUnit.type); var damageMultiplier = isCritical ? getCriticalDamageMultiplier() : 1.0; var actualDamage = Math.floor(selectedUnit.attackStrength * damageMultiplier); if (selectedUnit.hasInstantKill && !targetUnit.isKing) { removeUnit(targetUnit); } else if (targetUnit.isKing) { if (selectedUnit.type === 'warrior') { removeUnit(targetUnit); } else { var isCritical = isCriticalDamage(selectedUnit.type, targetUnit.type); var damageMultiplier = isCritical ? getCriticalDamageMultiplier() : 1.0; var actualDamage = Math.floor(selectedUnit.attackStrength * damageMultiplier); targetUnit.health -= actualDamage; targetUnit.healthText.setText(targetUnit.health.toString()); if (targetUnit.health <= 0) removeUnit(targetUnit); } } else if (selectedUnit.isAreaAttacker) { var adjacentCells = getAdjacentCells(cell.row, cell.col); targetUnit.health -= actualDamage; targetUnit.healthText.setText(targetUnit.health.toString()); if (isCritical) { var critEffect = new CriticalDamageEffect().init(actualDamage, targetUnit.x, targetUnit.y - 50); game.addChild(critEffect); tween(targetUnit, { scaleX: 0.8, scaleY: 0.8, rotation: 0.2 }, { duration: 100, easing: tween.easeOutQuad, onFinish: function onFinish() { tween(targetUnit, { scaleX: 1.0, scaleY: 1.0, rotation: 0 }, { duration: 200, easing: tween.elasticOut }); } }); } if (targetUnit.health <= 0) removeUnit(targetUnit); for (var i = 0; i < adjacentCells.length; i++) { var adjCell = adjacentCells[i]; if (adjCell.occupied && adjCell.occupiedBy.team !== selectedUnit.team) { var adjTargetUnit = adjCell.occupiedBy; var adjDamage = Math.floor(actualDamage / 2); adjTargetUnit.health -= adjDamage; adjTargetUnit.healthText.setText(adjTargetUnit.health.toString()); if (adjTargetUnit.health <= 0) removeUnit(adjTargetUnit); } } } else { targetUnit.health -= actualDamage; targetUnit.healthText.setText(targetUnit.health.toString()); if (isCritical) { var critEffect = new CriticalDamageEffect().init(actualDamage, targetUnit.x, targetUnit.y - 50); game.addChild(critEffect); tween(targetUnit, { scaleX: 0.7, scaleY: 0.7, rotation: 0.3 }, { duration: 100, easing: tween.easeOutQuad, onFinish: function onFinish() { tween(targetUnit, { scaleX: 1.0, scaleY: 1.0, rotation: 0 }, { duration: 300, easing: tween.elasticOut }); } }); } if (targetUnit.health <= 0) removeUnit(targetUnit); } selectedUnit.deselect(); clearAllHighlights(); selectedUnit = null; endTurn(); } }); } }); } function checkForAutoAttack() {} function getAdjacentCells(row, col) { var adjacent = []; var directions = [{ r: -1, c: 0 }, { r: 1, c: 0 }, { r: 0, c: -1 }, { r: 0, c: 1 }, { r: -1, c: -1 }, { r: -1, c: 1 }, { r: 1, c: -1 }, { r: 1, c: 1 }]; for (var i = 0; i < directions.length; i++) { var newRow = row + directions[i].r, newCol = col + directions[i].c; if (newRow >= 0 && newRow < GRID_ROWS && newCol >= 0 && newCol < GRID_COLS) { adjacent.push(grid[newRow][newCol]); } } return adjacent; } function removeUnit(unit) { grid[unit.row][unit.col].occupied = false; grid[unit.row][unit.col].occupiedBy = null; var index = units.indexOf(unit); if (index > -1) units.splice(index, 1); game.removeChild(unit); if (unit.isKing) { if (unit.team === 'blue') endGame('red');else endGame('blue'); } } function clearAllHighlights() { for (var row = 0; row < GRID_ROWS; row++) { for (var col = 0; col < GRID_COLS; col++) { grid[row][col].clearHighlight(); } } } function endTurn() { var currentState = gameState; if (currentState === 'playerTurn') { gameState = 'aiTurn'; statusText.setText('AI Turn'); LK.setTimeout(function () { if (gameState === 'aiTurn') { if (ai.makeMove()) {} else { gameState = 'playerTurn'; statusText.setText('Player Turn'); } } }, 500); } else if (currentState === 'aiTurn') { gameState = 'playerTurn'; statusText.setText('Player Turn'); } } function endGame(winner) { gameState = 'gameOver'; if (winner === 'blue') { statusText.setText('You Win!'); LK.showYouWin(); } else { statusText.setText('Game Over'); LK.showGameOver(); } } function isCriticalDamage(attackerType, targetType) { if (attackerType === 'knight' && targetType === 'archer') return true; if (attackerType === 'archer' && targetType === 'wizard') return true; if (attackerType === 'wizard' && targetType === 'knight') return true; return false; } game.isCriticalDamage = isCriticalDamage; function getCriticalDamageMultiplier() { return 2.0; } game.getTeamUnits = function (team) { return units.filter(function (unit) { return unit.team === team; }); }; game.getKing = function (team) { for (var i = 0; i < units.length; i++) { if (units[i].isKing && units[i].team === team) return units[i]; } return null; }; game.selectUnit = selectUnit; game.moveSelectedUnit = moveSelectedUnit; game.attackCell = attackCell; game.grid = grid; game.gameState = gameState; game.getAdjacentCells = getAdjacentCells; Object.defineProperty(game, 'gameState', { get: function get() { return gameState; }, set: function set(value) { gameState = value; } }); game.updateTutorialPosition = function (x, y) { tutorialOffset.x = x || tutorialOffset.x; tutorialOffset.y = y || tutorialOffset.y; if (tutorialScreen && tutorialScreen.parent) { tutorialScreen.scrollContainer.x = 1024 + tutorialOffset.x; tutorialScreen.scrollContainer.y = -tutorialScreen.scrollY + tutorialOffset.y; var backButton = tutorialScreen.children[tutorialScreen.children.length - 2]; backButton.x = 200 + tutorialOffset.x; backButton.y = 2500 + tutorialOffset.y; var scrollIndicator = tutorialScreen.children[tutorialScreen.children.length - 1]; scrollIndicator.x = 1950 + tutorialOffset.x; scrollIndicator.y = 1366 + tutorialOffset.y; } }; game.showTitleScreen = function () { game.removeAllGameElements(); game.addChild(titleScreen); game.removeChild(tutorialScreen); game.removeChild(settingsScreen); statusText.visible = false; gameState = 'mainMenu'; var logo = titleScreen.children[0]; var titleText = titleScreen.children[1]; tween(logo, { y: -500 }, { duration: 800, easing: tween.elasticOut }); tween(titleText, { y: 800 }, { duration: 800, easing: tween.elasticOut }); }; game.showTutorial = function () { game.removeChild(titleScreen); game.addChild(tutorialScreen); game.removeChild(settingsScreen); gameState = 'tutorial'; }; game.showSettings = function () { game.removeChild(titleScreen); game.removeChild(tutorialScreen); game.addChild(settingsScreen); gameState = 'settings'; }; game.startGame = function () { game.removeChild(titleScreen); game.removeChild(tutorialScreen); game.removeChild(settingsScreen); for (var row = 0; row < GRID_ROWS; row++) { grid[row] = []; for (var col = 0; col < GRID_COLS; col++) { var cell = new GridCell(); cell.row = row; cell.col = col; cell.x = GRID_PADDING_X + col * CELL_SIZE + CELL_SIZE / 2; cell.y = GRID_PADDING_Y + row * CELL_SIZE + CELL_SIZE / 2; if ((row + col) % 2 === 0) { cell.removeChild(cell.children[0]); cell.attachAsset('grid_cell_dark', { anchorX: 0.5, anchorY: 0.5, alpha: 0.5 }); } grid[row][col] = cell; game.addChild(cell); } } createUnits(); statusText.visible = true; statusText.setText('Player Turn'); gameState = 'playerTurn'; }; game.removeAllGameElements = function () { for (var row = 0; row < grid.length; row++) { for (var col = 0; col < grid[row].length; col++) { if (grid[row][col]) game.removeChild(grid[row][col]); } } for (var i = 0; i < units.length; i++) { game.removeChild(units[i]); } grid = []; units = []; selectedUnit = null; }; initializeGame();
===================================================================
--- original.js
+++ change.js
@@ -7,26 +7,16 @@
* Classes
****/
var AIPlayer = Container.expand(function () {
var self = Container.call(this);
- // Make sure the AI player has access to the game object
- self.game = null; // Will be set when AI is initialized
+ self.game = null;
self.makeMove = function () {
- // Only make a move if it's AI's turn
- if (game.gameState !== 'aiTurn') {
- return false;
- }
- // Use fixed difficulty level (maximum difficulty)
+ if (game.gameState !== 'aiTurn') return false;
var difficultyLevel = 1.0;
- // At lower difficulty, there's a chance to make a random move instead of the best move
- var makeRandomMove = Math.random() > difficultyLevel;
var units = game.getTeamUnits('red');
- var moveFound = false;
- // At very low difficulty, just make random moves
if (difficultyLevel < 0.3 && Math.random() < 0.7) {
- // Make a completely random move with a random unit
- var movableUnits = units.filter(function (unit) {
- return unit.getPossibleMoves(game.grid).length > 0;
+ var movableUnits = units.filter(function (u) {
+ return u.getPossibleMoves(game.grid).length > 0;
});
if (movableUnits.length > 0) {
var randomUnit = movableUnits[Math.floor(Math.random() * movableUnits.length)];
var possibleMoves = randomUnit.getPossibleMoves(game.grid);
@@ -35,54 +25,44 @@
game.moveSelectedUnit(randomMove.row, randomMove.col);
return true;
}
}
- // First priority: attack if possible
for (var i = 0; i < units.length; i++) {
var unit = units[i];
var attacks = unit.getPossibleAttacks(game.grid);
if (attacks.length > 0) {
- // Prioritize attacking king
- var kingAttack = attacks.find(function (attack) {
- return game.grid[attack.row][attack.col].occupiedBy && game.grid[attack.row][attack.col].occupiedBy.isKing;
+ var kingAttack = attacks.find(function (a) {
+ return game.grid[a.row][a.col].occupiedBy && game.grid[a.row][a.col].occupiedBy.isKing;
});
if (kingAttack) {
game.selectUnit(unit);
game.attackCell(game.grid[kingAttack.row][kingAttack.col]);
return true;
}
- // Look for advantageous critical attacks first
- var criticalAttack = attacks.find(function (attack) {
- var target = game.grid[attack.row][attack.col].occupiedBy;
+ var criticalAttack = attacks.find(function (a) {
+ var target = game.grid[a.row][a.col].occupiedBy;
return target && game.isCriticalDamage(unit.type, target.type);
});
if (criticalAttack) {
game.selectUnit(unit);
game.attackCell(game.grid[criticalAttack.row][criticalAttack.col]);
return true;
}
- // For warriors, prioritize attacks to use their instant kill
if (unit.type === 'warrior' && attacks.length > 0) {
game.selectUnit(unit);
game.attackCell(game.grid[attacks[0].row][attacks[0].col]);
return true;
}
- // For wizards, prioritize attack positions that can hit multiple enemies
if (unit.type === 'wizard' && attacks.length > 0) {
- // Try to find attack that might hit multiple enemies due to area effect
- var bestAttack = attacks[0];
- var bestCount = 0;
+ var bestAttack = attacks[0],
+ bestCount = 0;
for (var j = 0; j < attacks.length; j++) {
var attack = attacks[j];
- // Use self.game reference to access getAdjacentCells
var adjacentCells = self.game.getAdjacentCells(attack.row, attack.col);
var enemyCount = 0;
- // Count adjacent enemy units
for (var k = 0; k < adjacentCells.length; k++) {
var cell = adjacentCells[k];
- if (cell.occupied && cell.occupiedBy.team === 'blue') {
- enemyCount++;
- }
+ if (cell.occupied && cell.occupiedBy.team === 'blue') enemyCount++;
}
if (enemyCount > bestCount) {
bestCount = enemyCount;
bestAttack = attack;
@@ -91,86 +71,53 @@
game.selectUnit(unit);
game.attackCell(game.grid[bestAttack.row][bestAttack.col]);
return true;
}
- // Otherwise attack first available target
game.selectUnit(unit);
game.attackCell(game.grid[attacks[0].row][attacks[0].col]);
return true;
}
}
- // Second priority: move toward player king
var playerKing = game.getKing('blue');
if (playerKing) {
- // Find unit closest to player king that can move
- var closestUnit = null;
- var closestDistance = Infinity;
+ var closestUnit = null,
+ closestDistance = Infinity;
for (var i = 0; i < units.length; i++) {
var unit = units[i];
var moves = unit.getPossibleMoves(game.grid);
if (moves.length > 0) {
var dist = Math.abs(unit.row - playerKing.row) + Math.abs(unit.col - playerKing.col);
- // Give priority to certain unit types based on their strengths
- if (unit.type === 'knight') {
- // Knights are mobile, so give them priority
- dist -= 2;
- } else if (unit.type === 'archer') {
- // Archers should try to get in position but not too close
- if (dist > 4) {
- dist -= 1;
- } // Encourage moving closer if far away
- else if (dist < 3) {
- dist += 2;
- } // Discourage getting too close
- } else if (unit.type === 'warrior') {
- // Warriors should get close for their instant kill
- dist -= 3;
- } else if (unit.type === 'wizard') {
- // Wizards should stay at medium distance for area attacks
- if (dist > 3 && dist < 6) {
- dist -= 2;
- }
+ if (unit.type === 'knight') dist -= 2;else if (unit.type === 'archer') {
+ if (dist > 4) dist -= 1;else if (dist < 3) dist += 2;
+ } else if (unit.type === 'warrior') dist -= 3;else if (unit.type === 'wizard') {
+ if (dist > 3 && dist < 6) dist -= 2;
}
if (dist < closestDistance) {
closestUnit = unit;
closestDistance = dist;
}
}
}
if (closestUnit) {
- var bestMove = null;
- var bestMoveScore = -Infinity;
+ var bestMove = null,
+ bestMoveScore = -Infinity;
var moves = closestUnit.getPossibleMoves(game.grid);
- // Score each possible move
for (var i = 0; i < moves.length; i++) {
var move = moves[i];
var moveScore = closestDistance - (Math.abs(move.row - playerKing.row) + Math.abs(move.col - playerKing.col));
- // Special movement strategy based on unit type and difficulty
- // Use fixed difficulty level (maximum difficulty)
var difficultyLevel = 1.0;
if (closestUnit.type === 'knight') {
- // Knights should try to position for attack next turn
var potentialAttackRange = Math.abs(move.row - playerKing.row) + Math.abs(move.col - playerKing.col);
- if (potentialAttackRange <= closestUnit.attackRange + 1) {
- // Strategic bonus scales with difficulty
- moveScore += 3 * difficultyLevel;
- }
+ if (potentialAttackRange <= closestUnit.attackRange + 1) moveScore += 3 * difficultyLevel;
} else if (closestUnit.type === 'archer') {
- // Archers want to be at their optimal attack range
var distAfterMove = Math.abs(move.row - playerKing.row) + Math.abs(move.col - playerKing.col);
- if (distAfterMove >= 3 && distAfterMove <= 5) {
- // Strategic bonus scales with difficulty
- moveScore += 4 * difficultyLevel;
- }
+ if (distAfterMove >= 3 && distAfterMove <= 5) moveScore += 4 * difficultyLevel;
} else if (closestUnit.type === 'wizard') {
- // Wizards prefer positions that might hit multiple units next turn
var adjacentCells = self.game.getAdjacentCells(move.row, move.col);
var playerUnitsNearby = 0;
for (var j = 0; j < adjacentCells.length; j++) {
var cell = adjacentCells[j];
- if (cell.occupied && cell.occupiedBy.team === 'blue') {
- playerUnitsNearby++;
- }
+ if (cell.occupied && cell.occupiedBy.team === 'blue') playerUnitsNearby++;
}
moveScore += playerUnitsNearby * 2;
}
if (moveScore > bestMoveScore) {
@@ -184,52 +131,32 @@
return true;
}
}
}
- // Check if any unit is in danger and try to move it to safety
var unitsInDanger = units.filter(function (unit) {
- // Check if any player unit could attack this unit in the next turn
var playerUnits = game.getTeamUnits('blue');
for (var i = 0; i < playerUnits.length; i++) {
var playerUnit = playerUnits[i];
- // Calculate if the player unit could potentially attack this AI unit
var rowDiff = Math.abs(playerUnit.row - unit.row);
var colDiff = Math.abs(playerUnit.col - unit.col);
- // Check if in potential attack range based on unit type
var inDanger = false;
- if (playerUnit.type === 'warrior' && rowDiff + colDiff <= playerUnit.moveRange + playerUnit.attackRange) {
- inDanger = true;
- } else if (playerUnit.type === 'archer' && colDiff === 0 && rowDiff <= playerUnit.attackRange + 1) {
- inDanger = true;
- } else if (playerUnit.type === 'knight' && (rowDiff === 0 || colDiff === 0) && rowDiff + colDiff <= playerUnit.attackRange + 1) {
- inDanger = true;
- } else if (playerUnit.type === 'wizard' && rowDiff + colDiff <= playerUnit.moveRange + 2) {
- inDanger = true;
- }
- // If king is in danger, prioritize its safety
- if (inDanger && unit.isKing) {
- return true;
- } else if (inDanger && unit.health < 50) {
- return true;
- }
+ if (playerUnit.type === 'warrior' && rowDiff + colDiff <= playerUnit.moveRange + playerUnit.attackRange) inDanger = true;else if (playerUnit.type === 'archer' && colDiff === 0 && rowDiff <= playerUnit.attackRange + 1) inDanger = true;else if (playerUnit.type === 'knight' && (rowDiff === 0 || colDiff === 0) && rowDiff + colDiff <= playerUnit.attackRange + 1) inDanger = true;else if (playerUnit.type === 'wizard' && rowDiff + colDiff <= playerUnit.moveRange + 2) inDanger = true;
+ if (inDanger && unit.isKing) return true;else if (inDanger && unit.health < 50) return true;
}
return false;
});
if (unitsInDanger.length > 0) {
- // Prioritize king safety
- var unitToSave = unitsInDanger.find(function (unit) {
- return unit.isKing;
+ var unitToSave = unitsInDanger.find(function (u) {
+ return u.isKing;
}) || unitsInDanger[0];
var moves = unitToSave.getPossibleMoves(game.grid);
if (moves.length > 0) {
- // Find safest move (furthest from player units)
var playerUnits = game.getTeamUnits('blue');
- var bestMove = null;
- var bestSafetyScore = -Infinity;
+ var bestMove = null,
+ bestSafetyScore = -Infinity;
for (var i = 0; i < moves.length; i++) {
- var move = moves[i];
- var safetyScore = 0;
- // Calculate safety based on distance from all player units
+ var move = moves[i],
+ safetyScore = 0;
for (var j = 0; j < playerUnits.length; j++) {
var playerUnit = playerUnits[j];
var dist = Math.abs(move.row - playerUnit.row) + Math.abs(move.col - playerUnit.col);
safetyScore += dist;
@@ -245,11 +172,10 @@
return true;
}
}
}
- // Last resort: random move with random unit
- var movableUnits = units.filter(function (unit) {
- return unit.getPossibleMoves(game.grid).length > 0;
+ var movableUnits = units.filter(function (u) {
+ return u.getPossibleMoves(game.grid).length > 0;
});
if (movableUnits.length > 0) {
var randomUnit = movableUnits[Math.floor(Math.random() * movableUnits.length)];
var possibleMoves = randomUnit.getPossibleMoves(game.grid);
@@ -257,46 +183,40 @@
game.selectUnit(randomUnit);
game.moveSelectedUnit(randomMove.row, randomMove.col);
return true;
}
- return false; // No move possible
+ return false;
};
return self;
});
var CriticalDamageEffect = Container.expand(function () {
var self = Container.call(this);
self.init = function (damage, x, y) {
- // Create the critical hit text with animation
var critText = new Text2('CRITICAL HIT!', {
size: 80,
fill: '#FF0000'
});
critText.anchor.set(0.5, 0.5);
self.addChild(critText);
- // Create the damage text
var damageText = new Text2('-' + damage, {
size: 100,
fill: '#FFFF00'
});
damageText.anchor.set(0.5, 0.5);
damageText.y = 80;
self.addChild(damageText);
- // Position the effect
self.x = x;
self.y = y;
- // Initial scale and alpha
self.scale.set(0.1);
self.alpha = 0;
- // Animate in
tween(self, {
scaleX: 1.2,
scaleY: 1.2,
alpha: 1
}, {
duration: 300,
easing: tween.elasticOut
});
- // Animate out after showing
LK.setTimeout(function () {
tween(self, {
scaleX: 1.5,
scaleY: 1.5,
@@ -315,46 +235,31 @@
return self;
});
var GridCell = Container.expand(function () {
var self = Container.call(this);
- // Cell properties
self.row = 0;
self.col = 0;
self.occupied = false;
self.occupiedBy = null;
self.highlighted = false;
self.highlightType = null;
- // Create cell graphic
var cellGraphic = self.attachAsset('grid_cell', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.5
});
- // Highlighting methods
self.highlight = function (type) {
- if (self.highlightAsset) {
- self.removeChild(self.highlightAsset);
- }
+ if (self.highlightAsset) self.removeChild(self.highlightAsset);
self.highlighted = true;
self.highlightType = type;
- if (type === 'move') {
- self.highlightAsset = self.attachAsset('highlight_move', {
+ var asset = null;
+ if (type === 'move') asset = 'highlight_move';else if (type === 'attack') asset = 'highlight_attack';else if (type === 'selected') asset = 'highlight_selected';
+ if (asset) {
+ self.highlightAsset = self.attachAsset(asset, {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.5
});
- } else if (type === 'attack') {
- self.highlightAsset = self.attachAsset('highlight_attack', {
- anchorX: 0.5,
- anchorY: 0.5,
- alpha: 0.5
- });
- } else if (type === 'selected') {
- self.highlightAsset = self.attachAsset('highlight_selected', {
- anchorX: 0.5,
- anchorY: 0.5,
- alpha: 0.5
- });
}
};
self.clearHighlight = function () {
if (self.highlightAsset) {
@@ -363,39 +268,32 @@
}
self.highlighted = false;
self.highlightType = null;
};
- // Event handlers
- self.down = function (x, y, obj) {
- if (game.gameState === 'playerTurn') {
- game.handleCellClick(self);
- }
+ self.down = function () {
+ if (game.gameState === 'playerTurn') game.handleCellClick(self);
};
return self;
});
var SettingsScreen = Container.expand(function () {
var self = Container.call(this);
- // Title
var titleText = new Text2('SETTINGS', {
size: 150,
fill: '#FFFFFF'
});
titleText.anchor.set(0.5, 0);
titleText.y = -2732 / 3;
self.addChild(titleText);
- // Create toggle button
var createToggle = function createToggle(text, yPos, initialState, xPos) {
var container = new Container();
container.y = yPos;
container.x = xPos;
- // Label
var label = new Text2(text, {
size: 80,
fill: '#FFFFFF'
});
label.anchor.set(0, 0.5);
container.addChild(label);
- // Toggle background
var toggleBg = LK.getAsset('grid_cell_dark', {
anchorX: 0.5,
anchorY: 0.5,
width: 200,
@@ -403,9 +301,8 @@
alpha: 0.8
});
toggleBg.x = 900;
container.addChild(toggleBg);
- // Toggle indicator
var indicator = LK.getAsset('grid_cell', {
anchorX: 0.5,
anchorY: 0.5,
width: 80,
@@ -413,12 +310,10 @@
});
indicator.x = initialState ? 950 : 850;
indicator.y = 0;
container.addChild(indicator);
- // State
container.state = initialState;
- // Toggle functionality
- toggleBg.down = function (x, y, obj) {
+ toggleBg.down = function () {
container.state = !container.state;
tween(indicator, {
x: container.state ? 950 : 850
}, {
@@ -427,77 +322,10 @@
});
};
return container;
};
- // Create difficulty slider
- var createSlider = function createSlider(text, yPos, initialValue, xPos) {
- var container = new Container();
- container.y = yPos;
- container.x = xPos;
- // Label
- var label = new Text2(text, {
- size: 80,
- fill: '#FFFFFF'
- });
- label.anchor.set(0, 0.5);
- container.addChild(label);
- // Slider background
- var sliderBg = LK.getAsset('grid_cell_dark', {
- anchorX: 0,
- anchorY: 0.5,
- width: 500,
- height: 40,
- alpha: 0.8
- });
- sliderBg.x = 650;
- container.addChild(sliderBg);
- // Slider handle
- var handle = LK.getAsset('grid_cell', {
- anchorX: 0.5,
- anchorY: 0.5,
- width: 80,
- height: 80
- });
- handle.x = 650 + initialValue * 500;
- container.addChild(handle);
- // Value display
- var valueText = new Text2(initialValue.toString(), {
- size: 60,
- fill: '#FFFFFF'
- });
- valueText.anchor.set(0, 0.5);
- valueText.x = 1200;
- container.addChild(valueText);
- // State
- container.value = initialValue;
- // Slider functionality
- var isDragging = false;
- handle.down = function (x, y, obj) {
- isDragging = true;
- };
- container.move = function (x, y, obj) {
- if (isDragging && obj && obj.position) {
- var localPos = sliderBg.toLocal(obj.position);
- if (localPos) {
- var newX = Math.max(0, Math.min(500, localPos.x));
- handle.x = 650 + newX;
- container.value = Math.round(newX / 500 * 10) / 10;
- valueText.setText(container.value.toString());
- }
- }
- };
- container.up = function (x, y, obj) {
- isDragging = false;
- };
- return container;
- };
- // Create settings controls
- var soundToggle = createToggle('Sound Effects', 400, true, -500);
var musicToggle = createToggle('Music', 550, true, -500);
- // Add controls to container
- self.addChild(soundToggle);
self.addChild(musicToggle);
- // Back button
var backButton = new Container();
var backBg = LK.getAsset('grid_cell', {
anchorX: 0.5,
anchorY: 0.5,
@@ -512,21 +340,19 @@
backText.anchor.set(0.5, 0.5);
backButton.addChild(backBg);
backButton.addChild(backText);
backButton.x = 0;
- backButton.y = 800;
+ backButton.y = musicToggle.y + 200;
self.addChild(backButton);
- // Back button functionality
- backButton.down = function (x, y, obj) {
+ backButton.down = function () {
tween(backBg, {
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 100,
easing: tween.easeOutQuad
});
};
- // Add grow and shrink animation to back button
function animateBackButton() {
tween(backBg, {
scaleX: 1.1,
scaleY: 1.1
@@ -544,11 +370,10 @@
});
}
});
}
- // Start the animation
animateBackButton();
- backButton.up = function (x, y, obj) {
+ backButton.up = function () {
tween(backBg, {
scaleX: 1,
scaleY: 1
}, {
@@ -562,55 +387,47 @@
return self;
});
var TitleScreen = Container.expand(function () {
var self = Container.call(this);
- // Logo image
var logo = LK.getAsset('game_logo', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -200
});
self.addChild(logo);
- // Title text placeholder to maintain layout structure
var titleText = new Text2('', {
size: 200,
fill: '#FFFFFF'
});
- titleText.anchor.set(0.5, 0.5);
self.addChild(titleText);
- // Create buttons for different game modes
- var createButton = function createButton(text, yOffset) {
+ function createButton(text, yOffset) {
var button = new Container();
- // Button background
var bg = LK.getAsset('grid_cell', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.8,
width: 800,
height: 150
});
button.addChild(bg);
- // Button text
var buttonText = new Text2(text, {
size: 100,
fill: '#000000'
});
buttonText.anchor.set(0.5, 0.5);
button.addChild(buttonText);
- // Position button
button.y = yOffset;
- // Button hover/press effects
- button.down = function (x, y, obj) {
+ button.down = function () {
tween(bg, {
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 100,
easing: tween.easeOutQuad
});
};
- button.up = function (x, y, obj) {
+ button.up = function () {
tween(bg, {
scaleX: 1,
scaleY: 1
}, {
@@ -618,18 +435,15 @@
easing: tween.elasticOut
});
};
return button;
- };
- // Create menu buttons
+ }
var playButton = createButton('PLAY GAME', 100);
var tutorialButton = createButton('TUTORIAL', 300);
var settingsButton = createButton('SETTINGS', 500);
- // Add buttons to container
self.addChild(playButton);
self.addChild(tutorialButton);
self.addChild(settingsButton);
- // Animate buttons with grow and shrink effect
function animateButton(button, delay) {
LK.setTimeout(function () {
tween(button, {
scaleX: 1.1,
@@ -651,23 +465,21 @@
}
});
}, delay);
}
- // Start button animations with staggered delays
animateButton(playButton, 0);
animateButton(tutorialButton, 300);
animateButton(settingsButton, 600);
- // Button functionality
- playButton.down = function (x, y, obj) {
+ playButton.down = function () {
tween(playButton.children[0], {
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 100,
easing: tween.easeOutQuad
});
};
- playButton.up = function (x, y, obj) {
+ playButton.up = function () {
tween(playButton.children[0], {
scaleX: 1,
scaleY: 1
}, {
@@ -677,18 +489,18 @@
game.startGame();
}
});
};
- tutorialButton.down = function (x, y, obj) {
+ tutorialButton.down = function () {
tween(tutorialButton.children[0], {
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 100,
easing: tween.easeOutQuad
});
};
- tutorialButton.up = function (x, y, obj) {
+ tutorialButton.up = function () {
tween(tutorialButton.children[0], {
scaleX: 1,
scaleY: 1
}, {
@@ -698,18 +510,18 @@
game.showTutorial();
}
});
};
- settingsButton.down = function (x, y, obj) {
+ settingsButton.down = function () {
tween(settingsButton.children[0], {
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 100,
easing: tween.easeOutQuad
});
};
- settingsButton.up = function (x, y, obj) {
+ settingsButton.up = function () {
tween(settingsButton.children[0], {
scaleX: 1,
scaleY: 1
}, {
@@ -721,740 +533,9 @@
});
};
return self;
});
-var TutorialScreen = Container.expand(function () {
- var self = Container.call(this);
- // Add background overlay for better readability
- var bg = LK.getAsset('grid_cell_dark', {
- anchorX: 0,
- anchorY: 0,
- width: 2048,
- height: 2732,
- alpha: 0.2
- });
- self.addChild(bg);
- // Main container to allow scrolling
- var scrollContainer = new Container();
- self.scrollContainer = scrollContainer; // Expose scrollContainer as a property
- self.addChild(scrollContainer);
- // Title container with fancier styling
- var titleContainer = new Container();
- titleContainer.y = 80;
- scrollContainer.addChild(titleContainer);
- // Title background for emphasis
- var titleBg = LK.getAsset('grid_cell', {
- anchorX: 0.5,
- anchorY: 0.5,
- width: 1800,
- height: 180,
- alpha: 0.0
- });
- titleContainer.addChild(titleBg);
- // Main title text
- var titleText = new Text2('Tactical Kings: Tutorials', {
- size: 120,
- fill: '#FFFFFF'
- });
- titleText.anchor.set(0.5, 0.5);
- titleContainer.addChild(titleText);
- // Content creation helper function with visual aids
- var createTutorialSection = function createTutorialSection(title, content, yPos, visualType) {
- var section = new Container();
- section.y = yPos;
- // Section header background
- var headerBg = LK.getAsset('highlight_move', {
- anchorX: 0.5,
- anchorY: 0.5,
- width: 1600,
- height: 120,
- alpha: 0.6
- });
- headerBg.y = 50;
- section.addChild(headerBg);
- // Section title with better styling
- var sectionTitle = new Text2(title, {
- size: 90,
- fill: '#FFFFFF'
- });
- sectionTitle.anchor.set(0.5, 0.5);
- sectionTitle.y = 50;
- section.addChild(sectionTitle);
- // Content background for better readability
- var contentBg = LK.getAsset('grid_cell_dark', {
- anchorX: 0.5,
- anchorY: 0,
- width: 1800,
- height: content.split('\n').length * 70 + 160,
- // Dynamic height based on content
- alpha: 0.0
- });
- contentBg.y = 120;
- section.addChild(contentBg);
- // Section content with improved formatting
- var sectionContent = new Text2(content, {
- size: 60,
- fill: '#FFFFFF',
- wordWrap: true,
- wordWrapWidth: 1600
- });
- sectionContent.anchor.set(0.5, 0);
- sectionContent.y = 140;
- section.addChild(sectionContent);
- // Visual aid based on section type
- if (visualType === 'core') {
- // Game objective visual - chessboard with highlighted king
- var boardVisual = new Container();
- boardVisual.y = contentBg.height + 750;
- // Mini grid visual
- for (var i = 0; i < 3; i++) {
- for (var j = 0; j < 3; j++) {
- var cell = LK.getAsset((i + j) % 2 === 0 ? 'grid_cell' : 'grid_cell_dark', {
- anchorX: 0.5,
- anchorY: 0.5,
- width: 120,
- height: 120,
- alpha: 0.7
- });
- cell.x = (j - 1) * 130;
- cell.y = (i - 1) * 130;
- boardVisual.addChild(cell);
- // Add highlight to center to show objective
- if (i === 1 && j === 1) {
- var highlight = LK.getAsset('highlight_selected', {
- anchorX: 0.5,
- anchorY: 0.5,
- width: 120,
- height: 120,
- alpha: 0.7
- });
- cell.addChild(highlight);
- // Add king piece
- var king = LK.getAsset('king_red', {
- anchorX: 0.5,
- anchorY: 0.5,
- width: 80,
- height: 80
- });
- cell.addChild(king);
- }
- }
- }
- section.addChild(boardVisual);
- // Adjust content background height to include visual
- contentBg.height += 400;
- } else if (visualType === 'characters') {
- // Character roster visual
- var charactersVisual = new Container();
- charactersVisual.y = contentBg.height + 1000;
- // Create visual for each character type
- var characters = [{
- type: 'knight_blue',
- name: 'Knight',
- x: -600
- }, {
- type: 'archer_blue',
- name: 'Archer',
- x: -300
- }, {
- type: 'wizard_blue',
- name: 'Mage',
- x: 0
- }, {
- type: 'warrior_blue',
- name: 'Tank',
- x: 300
- }, {
- type: 'king_blue',
- name: 'King',
- x: 600
- }];
- characters.forEach(function (_char) {
- var charContainer = new Container();
- charContainer.x = _char.x;
- // Background circle
- var bg = LK.getAsset('grid_cell', {
- anchorX: 0.5,
- anchorY: 0.5,
- width: 180,
- height: 180,
- alpha: 0.5
- });
- charContainer.addChild(bg);
- // Character icon
- var icon = LK.getAsset(_char.type, {
- anchorX: 0.5,
- anchorY: 0.5,
- width: 150,
- height: 150
- });
- charContainer.addChild(icon);
- // Character name
- var name = new Text2(_char.name, {
- size: 40,
- fill: '#FFFFFF'
- });
- name.anchor.set(0.5, 0);
- name.y = 100;
- charContainer.addChild(name);
- charactersVisual.addChild(charContainer);
- });
- section.addChild(charactersVisual);
- // Adjust content background height to include visual
- contentBg.height += 350;
- } else if (visualType === 'tactics') {
- // Tactics visual - counter relationship diagram
- var tacticsVisual = new Container();
- tacticsVisual.y = contentBg.height + 1000;
- // Create counter relationship triangle
- var counterPositions = [{
- type: 'knight_blue',
- name: 'Knight',
- x: -300,
- y: 0
- }, {
- type: 'archer_blue',
- name: 'Archer',
- x: 300,
- y: 0
- }, {
- type: 'wizard_blue',
- name: 'Mage',
- x: 0,
- y: -260
- }];
- // Draw relationship lines first (so they appear behind icons)
- var relationshipLines = new Container();
- // Draw triangle connecting the three unit types
- var p1 = counterPositions[0];
- var p2 = counterPositions[1];
- var p3 = counterPositions[2];
- // Create line assets as rectangles
- var line1 = LK.getAsset('grid_cell', {
- anchorX: 0.5,
- anchorY: 0.5,
- width: Math.sqrt(Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2)),
- height: 10,
- alpha: 0.6
- });
- line1.x = (p1.x + p2.x) / 2;
- line1.y = (p1.y + p2.y) / 2;
- line1.rotation = Math.atan2(p2.y - p1.y, p2.x - p1.x);
- relationshipLines.addChild(line1);
- var line2 = LK.getAsset('grid_cell', {
- anchorX: 0.5,
- anchorY: 0.5,
- width: Math.sqrt(Math.pow(p3.x - p2.x, 2) + Math.pow(p3.y - p2.y, 2)),
- height: 10,
- alpha: 0.6
- });
- line2.x = (p2.x + p3.x) / 2;
- line2.y = (p2.y + p3.y) / 2;
- line2.rotation = Math.atan2(p3.y - p2.y, p3.x - p2.x);
- relationshipLines.addChild(line2);
- var line3 = LK.getAsset('grid_cell', {
- anchorX: 0.5,
- anchorY: 0.5,
- width: Math.sqrt(Math.pow(p1.x - p3.x, 2) + Math.pow(p1.y - p3.y, 2)),
- height: 10,
- alpha: 0.6
- });
- line3.x = (p3.x + p1.x) / 2;
- line3.y = (p3.y + p1.y) / 2;
- line3.rotation = Math.atan2(p1.y - p3.y, p1.x - p3.x);
- relationshipLines.addChild(line3);
- tacticsVisual.addChild(relationshipLines);
- // Add character icons with labels
- counterPositions.forEach(function (pos) {
- var unitContainer = new Container();
- unitContainer.x = pos.x;
- unitContainer.y = pos.y;
- // Background circle
- var bg = LK.getAsset('grid_cell', {
- anchorX: 0.5,
- anchorY: 0.5,
- width: 180,
- height: 180,
- alpha: 0.5
- });
- unitContainer.addChild(bg);
- // Unit icon
- var icon = LK.getAsset(pos.type, {
- anchorX: 0.5,
- anchorY: 0.5,
- width: 150,
- height: 150
- });
- unitContainer.addChild(icon);
- // Unit name
- var name = new Text2(pos.name, {
- size: 40,
- fill: '#FFFFFF'
- });
- name.anchor.set(0.5, 0);
- name.y = 100;
- unitContainer.addChild(name);
- tacticsVisual.addChild(unitContainer);
- });
- section.addChild(tacticsVisual);
- // Adjust content background height to include visual
- contentBg.height += 500;
- }
- return section;
- };
- // Define content with better formatting and line breaks for readability
- var coreContent = "The objective of Tactical Kings is to capture the opponent's King while protecting your own.\n\n" + "• Turn-Based Gameplay: Players take turns moving units and attacking enemies\n\n" + "• Attack Zones: Each unit type has unique movement patterns and attack ranges\n\n" + "• Strategic Planning: Control territory and set up favorable exchanges\n\n" + "• Win Condition: Eliminate the enemy King to win the match";
- var characterContent = "• Knight: Moves horizontally and vertically up to 3 tiles. Attacks along movement paths. Strong against Archers.\n\n" + "• Archer: Moves sideways freely and 1 tile forward. Attacks up to 4 tiles ahead in a straight line. Counters Mages.\n\n" + "• Mage: Moves 2 tiles in any direction. Has area-effect attacks up to 3 tiles away, damaging adjacent enemies. Effective against Knights.\n\n" + "• Tank: Slow movement but high health. Can instantly defeat non-King units in front of it.\n\n" + "• King: Can teleport freely to any unoccupied cell on the board. Attacks 1 tile forward. Must be protected at all costs - losing it means defeat.";
- var tacticsContent = "• Unit Counters: Use the right units against enemies:\n - Knights beat Archers\n - Archers beat Mages\n - Mages beat Knights\n\n" + "• Territory Control: Position units to control key areas of the board\n\n" + "• King Protection: Always keep defensive units near your King\n\n" + "• Tactical Retreats: Sometimes moving away from danger is better than attacking\n\n" + "• Sacrifice Strategies: Trading pieces can be advantageous if it creates a winning position";
- // Calculate vertical spacing between sections
- var ySpacing = 340;
- // Add tutorial sections with improved spacing and visual aids - adjusted positioning
- var coreConceptsSection = createTutorialSection("Core Concepts", coreContent, ySpacing, 'core');
- var characterGuidesSection = createTutorialSection("Character Guides", characterContent, ySpacing + 1800, 'characters');
- var advancedTacticsSection = createTutorialSection("Advanced Tactics", tacticsContent, ySpacing + 3800, 'tactics');
- // Add sections to scroll container
- scrollContainer.addChild(coreConceptsSection);
- scrollContainer.addChild(characterGuidesSection);
- scrollContainer.addChild(advancedTacticsSection);
- // Center the scroll container horizontally and apply offset
- scrollContainer.x = 1024 + tutorialOffset.x;
- // Position the content vertically to avoid overlapping with offset
- scrollContainer.y = 0 + tutorialOffset.y;
- // Update content positioning
- titleContainer.y = 150;
- // Adjust section spacing to prevent overlapping
- var ySpacing = 450; // Increased spacing between sections
- // Back button with improved visibility
- var backButton = new Container();
- var backBg = LK.getAsset('grid_cell', {
- anchorX: 0.5,
- anchorY: 0.5,
- alpha: 0.9,
- width: 300,
- height: 120
- });
- var backText = new Text2('BACK', {
- size: 70,
- fill: '#000000'
- });
- backText.anchor.set(0.5, 0.5);
- backButton.addChild(backBg);
- backButton.addChild(backText);
- backButton.x = 200 + tutorialOffset.x; // Position in bottom-left with offset
- backButton.y = 2500 + tutorialOffset.y; // Adjusted position with offset
- self.addChild(backButton);
- // Back button functionality
- backButton.down = function (x, y, obj) {
- tween(backBg, {
- scaleX: 0.95,
- scaleY: 0.95
- }, {
- duration: 100,
- easing: tween.easeOutQuad
- });
- };
- // Add grow and shrink animation to back button
- function animateBackButton() {
- tween(backBg, {
- scaleX: 1.1,
- scaleY: 1.1
- }, {
- duration: 800,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- tween(backBg, {
- scaleX: 1.0,
- scaleY: 1.0
- }, {
- duration: 800,
- easing: tween.easeInOut,
- onFinish: animateBackButton
- });
- }
- });
- }
- // Start the animation
- animateBackButton();
- backButton.up = function (x, y, obj) {
- tween(backBg, {
- scaleX: 1,
- scaleY: 1
- }, {
- duration: 200,
- easing: tween.elasticOut,
- onFinish: function onFinish() {
- game.showTitleScreen();
- }
- });
- };
- // Add scroll indicator to show users the screen is scrollable
- var scrollIndicator = new Container();
- var arrowUp = LK.getAsset('highlight_attack', {
- anchorX: 0.5,
- anchorY: 0,
- width: 50,
- height: 30,
- alpha: 0.8
- });
- arrowUp.y = -35;
- scrollIndicator.addChild(arrowUp);
- var arrowDown = LK.getAsset('highlight_attack', {
- anchorX: 0.5,
- anchorY: 1,
- width: 50,
- height: 30,
- alpha: 0.8
- });
- arrowDown.y = 35;
- arrowDown.rotation = Math.PI;
- scrollIndicator.addChild(arrowDown);
- var indicatorText = new Text2("Scroll", {
- size: 40,
- fill: '#FFFFFF'
- });
- indicatorText.anchor.set(0.5, 0.5);
- scrollIndicator.addChild(indicatorText);
- scrollIndicator.x = 1950;
- scrollIndicator.y = 1366;
- self.addChild(scrollIndicator);
- // Animate scroll indicator to attract attention
- function animateScrollIndicator() {
- tween(scrollIndicator, {
- alpha: 0.3
- }, {
- duration: 1000,
- easing: tween.easeInOut,
- onFinish: function onFinish() {
- tween(scrollIndicator, {
- alpha: 1
- }, {
- duration: 1000,
- easing: tween.easeInOut,
- onFinish: animateScrollIndicator
- });
- }
- });
- }
- animateScrollIndicator();
- // Enhanced scroll functionality with momentum
- var scrollY = 0;
- self.scrollY = scrollY; // Expose scrollY as a property
- var scrollVelocity = 0;
- var maxScroll = 4000; // Reduced to prevent scrolling past content
- var isDragging = false;
- var lastY = 0;
- var lastTime = 0;
- self.down = function (x, y, obj) {
- lastY = y;
- lastTime = Date.now();
- scrollVelocity = 0;
- isDragging = true;
- };
- self.move = function (x, y, obj) {
- if (isDragging) {
- var currentTime = Date.now();
- var deltaTime = currentTime - lastTime;
- var deltaY = y - lastY;
- // Calculate velocity (pixels per millisecond)
- if (deltaTime > 0) {
- scrollVelocity = deltaY / deltaTime * 7.5; // Scale factor for better feel
- }
- scrollY -= deltaY;
- self.scrollY = scrollY; // Update property
- // Clamp scrolling with elastic effect
- if (scrollY < 0) {
- scrollY = scrollY * 0.5; // Resistance when pulling past top
- } else if (scrollY > maxScroll) {
- scrollY = maxScroll + (scrollY - maxScroll) * 0.5; // Resistance when pulling past bottom
- }
- // Apply scroll with offset vector
- scrollContainer.y = -scrollY + tutorialOffset.y;
- lastY = y;
- lastTime = currentTime;
- }
- };
- self.up = function (x, y, obj) {
- isDragging = false;
- // Apply elastic snapback if pulled past boundaries
- if (scrollY < 0) {
- tween(scrollContainer, {
- y: 0
- }, {
- duration: 300,
- easing: tween.elasticOut
- });
- scrollY = 0;
- self.scrollY = scrollY; // Update property
- scrollVelocity = 0;
- } else if (scrollY > maxScroll) {
- tween(scrollContainer, {
- y: -maxScroll
- }, {
- duration: 300,
- easing: tween.elasticOut
- });
- scrollY = maxScroll;
- self.scrollY = scrollY; // Update property
- scrollVelocity = 0;
- }
- // Apply momentum scrolling
- if (Math.abs(scrollVelocity) > 0.1) {
- applyScrollMomentum();
- }
- };
- // Handle momentum scrolling
- function applyScrollMomentum() {
- // Apply velocity with decay
- scrollY -= scrollVelocity * 10;
- scrollVelocity *= 0.95; // Decay factor
- // Boundary checking
- if (scrollY < 0) {
- scrollY = 0;
- self.scrollY = scrollY; // Update property
- scrollVelocity = 0;
- } else if (scrollY > maxScroll) {
- scrollY = maxScroll;
- self.scrollY = scrollY; // Update property
- scrollVelocity = 0;
- }
- // Apply scroll with offset vector
- scrollContainer.y = -scrollY + tutorialOffset.y;
- // Continue animation if velocity is significant
- if (Math.abs(scrollVelocity) > 0.1) {
- LK.setTimeout(applyScrollMomentum, 16); // ~60fps
- }
- }
- return self;
-});
-var Unit = Container.expand(function () {
- var self = Container.call(this);
- // Unit properties
- self.type = "";
- self.team = "";
- self.row = 0;
- self.col = 0;
- self.isKing = false;
- self.alive = true;
- self.selected = false;
- self.health = 100; // Base health for all units
- self.attackStrength = 20; // Base attack strength for all units
- // Initialize with type and team
- self.init = function (type, team, row, col) {
- self.type = type;
- self.team = team;
- self.row = row;
- self.col = col;
- self.isKing = type === 'king';
- // Set different health and attack values based on unit type
- switch (type) {
- case 'king':
- self.health = 250;
- self.attackStrength = 35;
- self.moveRange = Infinity; // Can move anywhere on the board
- self.attackRange = 1; // Can attack 1 tile forward
- break;
- case 'warrior':
- self.health = 280;
- self.attackStrength = 45;
- self.moveRange = 1; // Can move 1 tile in any direction
- self.attackRange = 1; // Can attack 1 tile forward
- break;
- case 'knight':
- self.health = 150;
- self.attackStrength = 40;
- self.moveRange = 3; // Can move up to 3 tiles horizontally or vertically
- self.attackRange = 2; // Can attack in movement range
- break;
- case 'wizard':
- self.health = 90;
- self.attackStrength = 60;
- self.moveRange = 2; // Can move up to 2 tiles in any direction
- self.attackRange = 3; // Attack 6 tiles ahead and surrounding
- break;
- case 'archer':
- self.health = 100;
- self.attackStrength = 50;
- self.moveRange = 1; // Can move sideways freely, 1 tile forward
- self.attackRange = 4; // Can attack up to 8 tiles ahead
- break;
- }
- var assetId = type + '_' + team;
- self.unitGraphic = self.attachAsset(assetId, {
- anchorX: 0.5,
- anchorY: 0.5,
- alpha: 1.0
- });
- return self;
- };
- // Movement validation
- self.canMoveTo = function (targetRow, targetCol) {
- // Base movement logic to be overridden by specific unit types
- return false;
- };
- // Attack validation
- self.canAttack = function (targetRow, targetCol) {
- // Base attack logic to be overridden by specific unit types
- return false;
- };
- // Get possible move cells
- self.getPossibleMoves = function (grid) {
- var moves = [];
- for (var r = 0; r < grid.length; r++) {
- for (var c = 0; c < grid[r].length; c++) {
- if (this.canMoveTo(r, c) && !grid[r][c].occupied) {
- moves.push({
- row: r,
- col: c
- });
- }
- }
- }
- return moves;
- };
- // Get possible attack cells
- self.getPossibleAttacks = function (grid) {
- var attacks = [];
- for (var r = 0; r < grid.length; r++) {
- for (var c = 0; c < grid[r].length; c++) {
- if (this.canAttack(r, c) && grid[r][c].occupied && grid[r][c].occupiedBy.team !== this.team) {
- attacks.push({
- row: r,
- col: c
- });
- }
- }
- }
- return attacks;
- };
- // Move unit to new position
- self.moveTo = function (targetRow, targetCol) {
- self.row = targetRow;
- self.col = targetCol;
- };
- // Select unit
- self.select = function () {
- self.selected = true;
- self.unitGraphic.alpha = 1.0;
- };
- // Deselect unit
- self.deselect = function () {
- self.selected = false;
- self.unitGraphic.alpha = 0.8;
- };
- return self;
-});
-var Wizard = Unit.expand(function () {
- var self = Unit.call(this);
- // Override movement validation
- self.canMoveTo = function (targetRow, targetCol) {
- var rowDiff = Math.abs(targetRow - self.row);
- var colDiff = Math.abs(targetCol - self.col);
- // Wizard can move diagonally or in straight lines
- return rowDiff <= 2 && colDiff <= 2;
- };
- // Override attack validation
- self.canAttack = function (targetRow, targetCol) {
- // Wizard can attack up to 3 tiles away in any direction
- var rowDiff = Math.abs(targetRow - self.row);
- var colDiff = Math.abs(targetCol - self.col);
- // Total distance (Manhattan distance) should be less than or equal to attack range
- return rowDiff + colDiff <= self.attackRange && !(rowDiff === 0 && colDiff === 0);
- };
- // Wizards do area damage
- self.isAreaAttacker = true;
- return self;
-});
-var Warrior = Unit.expand(function () {
- var self = Unit.call(this);
- // Override movement validation
- self.canMoveTo = function (targetRow, targetCol) {
- var rowDiff = Math.abs(targetRow - self.row);
- var colDiff = Math.abs(targetCol - self.col);
- // Warrior can only move up to moveRange tile in any direction
- return rowDiff <= self.moveRange && colDiff <= self.moveRange && !(rowDiff === 0 && colDiff === 0);
- };
- // Override attack validation
- self.canAttack = function (targetRow, targetCol) {
- // Instant-kill attack (1 tile forward)
- if (self.team === 'blue') {
- return targetRow === self.row - self.attackRange && targetCol === self.col;
- } else {
- return targetRow === self.row + self.attackRange && targetCol === self.col;
- }
- };
- // Warriors have instant kill ability
- self.hasInstantKill = true;
- return self;
-});
-var Knight = Unit.expand(function () {
- var self = Unit.call(this);
- // Override movement validation
- self.canMoveTo = function (targetRow, targetCol) {
- // Knight moves straight or sideways (1-3 tiles)
- var rowDiff = Math.abs(targetRow - self.row);
- var colDiff = Math.abs(targetCol - self.col);
- // Can move horizontally or vertically up to moveRange tiles
- return rowDiff === 0 && colDiff > 0 && colDiff <= self.moveRange || colDiff === 0 && rowDiff > 0 && rowDiff <= self.moveRange;
- };
- // Override attack validation
- self.canAttack = function (targetRow, targetCol) {
- // Knight can attack along the same paths as movement
- var rowDiff = Math.abs(targetRow - self.row);
- var colDiff = Math.abs(targetCol - self.col);
- return rowDiff === 0 && colDiff > 0 && colDiff <= self.attackRange || colDiff === 0 && rowDiff > 0 && rowDiff <= self.attackRange;
- };
- return self;
-});
-var King = Unit.expand(function () {
- var self = Unit.call(this);
- // Override movement validation
- self.canMoveTo = function (targetRow, targetCol) {
- // King can move anywhere on the board
- // Check if the target position is different from current position
- var rowDiff = Math.abs(targetRow - self.row);
- var colDiff = Math.abs(targetCol - self.col);
- // Allow movement to any unoccupied cell on the board
- return rowDiff > 0 || colDiff > 0;
- };
- // Override attack validation
- self.canAttack = function (targetRow, targetCol) {
- // King only attacks forward based on team direction and attack range
- var forwardRow = self.team === 'blue' ? self.row - self.attackRange : self.row + self.attackRange;
- return targetRow === forwardRow && targetCol === self.col;
- };
- return self;
-});
-var Archer = Unit.expand(function () {
- var self = Unit.call(this);
- // Override movement validation
- self.canMoveTo = function (targetRow, targetCol) {
- var rowDiff = Math.abs(targetRow - self.row);
- var colDiff = Math.abs(targetCol - self.col);
- // Can move sideways freely, but only moveRange tiles forward
- if (self.team === 'blue') {
- return colDiff > 0 && rowDiff === 0 ||
- // sideways
- targetRow === self.row - self.moveRange && colDiff === 0; // forward
- } else {
- return colDiff > 0 && rowDiff === 0 ||
- // sideways
- targetRow === self.row + self.moveRange && colDiff === 0; // forward
- }
- };
- // Override attack validation
- self.canAttack = function (targetRow, targetCol) {
- // Can attack any enemy in the line attackRange tiles forward
- if (self.team === 'blue') {
- // For blue team, attack any cell in the same column forward (up) within attack range
- return targetCol === self.col && targetRow < self.row && self.row - targetRow <= self.attackRange;
- } else {
- // For red team, attack any cell in the same column forward (down) within attack range
- return targetCol === self.col && targetRow > self.row && targetRow - self.row <= self.attackRange;
- }
- };
- return self;
-});
-// Vector2 class is now defined in the Classes section
+// Vector2 class
var Vector2 = Container.expand(function () {
var self = Container.call(this);
self.init = function (x, y) {
self.x = x || 0;
@@ -1485,92 +566,66 @@
/****
* Game Code
****/
-// Add global vector for tutorial content positioning
-// Import tween plugin
-// Game constants
-// Background image asset
var tutorialOffset = new Vector2().init(0, 0);
-var dragNode = null; // Initialize dragNode for drag functionality
+var dragNode = null;
var GRID_ROWS = 10;
var GRID_COLS = 5;
-var CELL_SIZE = 250; // Significantly increased cell size
+var CELL_SIZE = 250;
var GRID_PADDING_X = (2048 - GRID_COLS * CELL_SIZE) / 2;
var GRID_PADDING_Y = (2732 - GRID_ROWS * CELL_SIZE) / 2;
-// Game variables
var grid = [];
var units = [];
var selectedUnit = null;
-var gameState = 'mainMenu'; // mainMenu, tutorial, settings, playerTurn, aiTurn, gameOver
+var gameState = 'mainMenu';
var ai = new AIPlayer();
-ai.game = game; // Properly pass game reference to AI player
+ai.game = game;
var statusText = new Text2('Player Turn', {
size: 120,
- // Significantly increased text size
fill: 0xFFFFFF
});
-// Screen instances
var titleScreen = new TitleScreen();
-var tutorialScreen = new TutorialScreen();
+var tutorialScreen = new Container(); // Placeholder, implement as needed
var settingsScreen = new SettingsScreen();
-// Make settings screen accessible to the game object
game.settingsScreen = settingsScreen;
-// Fix the global move handler to properly handle slider dragging
game.move = function (x, y, obj) {
- // If we have a dragNode (for character dragging), handle that
if (dragNode) {
dragNode.x = x;
dragNode.y = y;
}
- // If we're in settings screen, handle movement
- if (settingsScreen && settingsScreen.parent && obj) {
- // No sliders to handle after removing AI difficulty slider
- }
};
-// Create handleMove function
function handleMove(x, y, obj) {
if (dragNode) {
dragNode.x = x;
dragNode.y = y;
}
}
-// Handle touch/mouse down state for sliders
game.down = function (x, y, obj) {
- // Only set dragNode if character exists and is defined
if (typeof character !== 'undefined') {
dragNode = character;
} else {
dragNode = null;
}
- // Mark objects as being touched down
- if (obj && obj.down) {
- obj.__isTouchDown = true;
- }
- // Also call move handler right away to make effect instant
- if (handleMove) {
- handleMove(x, y, obj);
- }
+ if (obj && obj.down) obj.__isTouchDown = true;
+ if (handleMove) handleMove(x, y, obj);
};
-// Handle touch/mouse up for sliders
game.up = function (x, y, obj) {
- // Original logic
dragNode = null;
- // Reset touch down states
- if (settingsScreen && settingsScreen.parent) {
- // No sliders to reset after removing AI difficulty slider
- }
};
-// Position screens at center
titleScreen.x = 1024;
titleScreen.y = 1366;
tutorialScreen.x = 0;
tutorialScreen.y = 0;
settingsScreen.x = 1024;
settingsScreen.y = 1366;
-// Initialize the game board
function initializeGame() {
- // Add background image first so it's behind other elements
+ for (var row = 0; row < GRID_ROWS; row++) {
+ grid[row] = [];
+ for (var col = 0; col < GRID_COLS; col++) {
+ grid[row][col] = {};
+ }
+ }
var background = LK.getAsset('background', {
anchorX: 0,
anchorY: 0,
x: 0,
@@ -1578,22 +633,11 @@
width: 2048,
height: 2732
});
game.addChild(background);
- // First show the title screen instead of starting the game directly
game.showTitleScreen();
- // Add status text (hidden initially, shown during gameplay)
- statusText.anchor.set(0.5, 0);
- statusText.x = 2048 / 2;
- statusText.y = 50;
- statusText.visible = false;
- LK.gui.top.addChild(statusText);
}
-// Create all units for both teams
function createUnits() {
- // Blue team (player) - bottom of the board
- // Formation: Knight, Warrior, Warrior, Warrior, Knight (row 8)
- // Formation: Archer, Mage, King, Mage, Archer (row 9)
createUnit('knight', 'blue', 8, 0);
createUnit('warrior', 'blue', 8, 1);
createUnit('warrior', 'blue', 8, 2);
createUnit('warrior', 'blue', 8, 3);
@@ -1602,11 +646,8 @@
createUnit('wizard', 'blue', 9, 1);
createUnit('king', 'blue', 9, 2);
createUnit('wizard', 'blue', 9, 3);
createUnit('archer', 'blue', 9, 4);
- // Red team (AI) - top of the board
- // Formation: Knight, Warrior, Warrior, Warrior, Knight (row 1)
- // Formation: Archer, Mage, King, Mage, Archer (row 0)
createUnit('knight', 'red', 1, 0);
createUnit('warrior', 'red', 1, 1);
createUnit('warrior', 'red', 1, 2);
createUnit('warrior', 'red', 1, 3);
@@ -1616,12 +657,10 @@
createUnit('king', 'red', 0, 2);
createUnit('wizard', 'red', 0, 3);
createUnit('archer', 'red', 0, 4);
}
-// Create a single unit
function createUnit(type, team, row, col) {
var unit;
- // Create the appropriate unit type
switch (type) {
case 'king':
unit = new King().init(type, team, row, col);
break;
@@ -1637,81 +676,53 @@
case 'warrior':
unit = new Warrior().init(type, team, row, col);
break;
}
- // Position unit
unit.x = grid[row][col].x;
unit.y = grid[row][col].y;
unit.unitGraphic.alpha = 0.8;
- // Add health display
unit.healthText = new Text2(unit.health.toString(), {
size: 50,
- fill: 0xFFD700 // Golden yellow color for better visibility
+ fill: 0xFFD700
});
unit.healthText.anchor.set(0.5, 0.5);
unit.healthText.y = unit.unitGraphic.height / 2 + 10;
unit.addChild(unit.healthText);
- // Add subtle entry animation
unit.unitGraphic.scale.set(0.1);
unit.unitGraphic.alpha = 0.3;
- // Add unit to game
game.addChild(unit);
units.push(unit);
- // Mark cell as occupied
grid[row][col].occupied = true;
grid[row][col].occupiedBy = unit;
- // Add click handler for player units
if (team === 'blue') {
unit.down = function (x, y, obj) {
- if (game.gameState === 'playerTurn') {
- selectUnit(unit);
- }
+ if (game.gameState === 'playerTurn') selectUnit(unit);
};
}
- // Animate unit entry with enhanced effect
tween(unit.unitGraphic, {
scaleX: 1.0,
scaleY: 1.0,
alpha: 0.8
}, {
duration: 600,
easing: tween.elasticOut,
- delay: 100 * (row + col) % 5 // Staggered appearance for visual interest
+ delay: 100 * (row + col) % 5
});
return unit;
}
-// Handle cell click
game.handleCellClick = function (cell) {
- if (!selectedUnit || game.gameState !== 'playerTurn') {
- return;
- }
- // If cell is highlighted for movement
- if (cell.highlighted && cell.highlightType === 'move') {
- moveSelectedUnit(cell.row, cell.col);
- }
- // If cell is highlighted for attack
- else if (cell.highlighted && cell.highlightType === 'attack') {
- attackCell(cell);
- }
+ if (!selectedUnit || game.gameState !== 'playerTurn') return;
+ if (cell.highlighted && cell.highlightType === 'move') moveSelectedUnit(cell.row, cell.col);else if (cell.highlighted && cell.highlightType === 'attack') attackCell(cell);
};
-// Select a unit
function selectUnit(unit) {
- // Can only select your own units
- if (unit.team !== 'blue' && gameState === 'playerTurn') {
- return;
- }
- if (unit.team !== 'red' && gameState === 'aiTurn') {
- return;
- }
- // Deselect previous unit if there was one
+ if (unit.team !== 'blue' && gameState === 'playerTurn') return;
+ if (unit.team !== 'red' && gameState === 'aiTurn') return;
if (selectedUnit) {
selectedUnit.deselect();
clearAllHighlights();
}
- // Select new unit
selectedUnit = unit;
selectedUnit.select();
- // Enhanced selection animation with glow effect
tween(selectedUnit.unitGraphic, {
scaleX: 1.2,
scaleY: 1.2,
alpha: 1.0
@@ -1720,56 +731,44 @@
easing: tween.elasticOut,
onFinish: function onFinish() {
tween(selectedUnit.unitGraphic, {
scaleX: 1.0,
- scaleY: 1.0,
- alpha: 0.9
+ scaleY: 1.0
}, {
duration: 200,
- easing: tween.easeOutQuad
+ easing: tween.elasticOut
});
}
});
- // Highlight cell under selected unit
grid[unit.row][unit.col].highlight('selected');
- // Highlight possible moves with delay for better visual feedback
var possibleMoves = unit.getPossibleMoves(grid);
for (var i = 0; i < possibleMoves.length; i++) {
(function (index) {
LK.setTimeout(function () {
if (selectedUnit === unit) {
- // Only highlight if still selected
var move = possibleMoves[index];
grid[move.row][move.col].highlight('move');
}
}, index * 30);
})(i);
}
- // Highlight possible attacks with delay
var possibleAttacks = unit.getPossibleAttacks(grid);
for (var i = 0; i < possibleAttacks.length; i++) {
(function (index) {
LK.setTimeout(function () {
if (selectedUnit === unit) {
- // Only highlight if still selected
var attack = possibleAttacks[index];
grid[attack.row][attack.col].highlight('attack');
}
}, (possibleMoves.length + index) * 30);
})(i);
}
}
-// Move selected unit to new position
function moveSelectedUnit(targetRow, targetCol) {
- if (!selectedUnit) {
- return;
- }
- // Update grid occupation
+ if (!selectedUnit) return;
grid[selectedUnit.row][selectedUnit.col].occupied = false;
grid[selectedUnit.row][selectedUnit.col].occupiedBy = null;
- // Move unit with animation
selectedUnit.moveTo(targetRow, targetCol);
- // Animate movement with tween
var targetX = grid[targetRow][targetCol].x;
var targetY = grid[targetRow][targetCol].y;
tween(selectedUnit, {
x: targetX,
@@ -1777,89 +776,66 @@
}, {
duration: 300,
easing: tween.easeOutQuad,
onFinish: function onFinish() {
- // Update grid occupation at new position
grid[targetRow][targetCol].occupied = true;
grid[targetRow][targetCol].occupiedBy = selectedUnit;
- // Deselect unit and clear highlights
selectedUnit.deselect();
clearAllHighlights();
selectedUnit = null;
- // Check if any attacks are possible after movement
checkForAutoAttack();
- // Switch turns
endTurn();
}
});
}
-// Attack a cell
function attackCell(cell) {
- if (!selectedUnit || !cell.occupied || cell.occupiedBy.team === selectedUnit.team) {
- return;
- }
+ if (!selectedUnit || !cell.occupied || cell.occupiedBy.team === selectedUnit.team) return;
var targetUnit = cell.occupiedBy;
- // Animate the attacker - "lunge" toward target
- var originalX = selectedUnit.x;
- var originalY = selectedUnit.y;
- var directionX = targetUnit.x - selectedUnit.x;
- var directionY = targetUnit.y - selectedUnit.y;
+ var originalX = selectedUnit.x,
+ originalY = selectedUnit.y;
+ var directionX = targetUnit.x - selectedUnit.x,
+ directionY = targetUnit.y - selectedUnit.y;
var distance = Math.sqrt(directionX * directionX + directionY * directionY);
- var normalizedX = directionX / distance * 30; // small lunge
- var normalizedY = directionY / distance * 30;
- // Enhanced attack animation sequence
+ var normalizedX = directionX / distance * 30,
+ normalizedY = directionY / distance * 30;
tween(selectedUnit, {
x: selectedUnit.x + normalizedX * 1.5,
- // More pronounced lunge
y: selectedUnit.y + normalizedY * 1.5
}, {
duration: 200,
easing: tween.easeOutQuad,
onFinish: function onFinish() {
- // More dramatic visual flash on target
LK.effects.flashObject(targetUnit, 0xff0000, 400);
- // Return attacker to original position
tween(selectedUnit, {
x: originalX,
y: originalY
}, {
duration: 200,
easing: tween.easeOutQuad,
onFinish: function onFinish() {
- // Check for critical damage
var isCritical = isCriticalDamage(selectedUnit.type, targetUnit.type);
var damageMultiplier = isCritical ? getCriticalDamageMultiplier() : 1.0;
var actualDamage = Math.floor(selectedUnit.attackStrength * damageMultiplier);
- // Perform attack after animation
if (selectedUnit.hasInstantKill && !targetUnit.isKing) {
- // Warrior's instant kill works on all enemies except kings
removeUnit(targetUnit);
} else if (targetUnit.isKing) {
- // King only dies in one hit if attacked by a warrior
if (selectedUnit.type === 'warrior') {
removeUnit(targetUnit);
} else {
- // Apply normal damage to king
var isCritical = isCriticalDamage(selectedUnit.type, targetUnit.type);
var damageMultiplier = isCritical ? getCriticalDamageMultiplier() : 1.0;
var actualDamage = Math.floor(selectedUnit.attackStrength * damageMultiplier);
targetUnit.health -= actualDamage;
targetUnit.healthText.setText(targetUnit.health.toString());
- if (targetUnit.health <= 0) {
- removeUnit(targetUnit);
- }
+ if (targetUnit.health <= 0) removeUnit(targetUnit);
}
} else if (selectedUnit.isAreaAttacker) {
- // Area attack affects target and adjacent units of opposite team
var adjacentCells = getAdjacentCells(cell.row, cell.col);
- // Apply damage instead of instant kill
targetUnit.health -= actualDamage;
targetUnit.healthText.setText(targetUnit.health.toString());
- // Show critical hit effect if applicable
if (isCritical) {
var critEffect = new CriticalDamageEffect().init(actualDamage, targetUnit.x, targetUnit.y - 50);
game.addChild(critEffect);
- // Add stronger visual feedback
tween(targetUnit, {
scaleX: 0.8,
scaleY: 0.8,
rotation: 0.2
@@ -1877,32 +853,25 @@
});
}
});
}
- if (targetUnit.health <= 0) {
- removeUnit(targetUnit);
- }
+ if (targetUnit.health <= 0) removeUnit(targetUnit);
for (var i = 0; i < adjacentCells.length; i++) {
var adjCell = adjacentCells[i];
if (adjCell.occupied && adjCell.occupiedBy.team !== selectedUnit.team) {
var adjTargetUnit = adjCell.occupiedBy;
- var adjDamage = Math.floor(actualDamage / 2); // Half damage for adjacent units
+ var adjDamage = Math.floor(actualDamage / 2);
adjTargetUnit.health -= adjDamage;
adjTargetUnit.healthText.setText(adjTargetUnit.health.toString());
- if (adjTargetUnit.health <= 0) {
- removeUnit(adjTargetUnit);
- }
+ if (adjTargetUnit.health <= 0) removeUnit(adjTargetUnit);
}
}
} else {
- // Normal attack
targetUnit.health -= actualDamage;
targetUnit.healthText.setText(targetUnit.health.toString());
- // Show critical hit effect if applicable
if (isCritical) {
var critEffect = new CriticalDamageEffect().init(actualDamage, targetUnit.x, targetUnit.y - 50);
game.addChild(critEffect);
- // Add stronger visual feedback for critical hit
tween(targetUnit, {
scaleX: 0.7,
scaleY: 0.7,
rotation: 0.3
@@ -1920,28 +889,20 @@
});
}
});
}
- if (targetUnit.health <= 0) {
- removeUnit(targetUnit);
- }
+ if (targetUnit.health <= 0) removeUnit(targetUnit);
}
- // Deselect unit and clear highlights
selectedUnit.deselect();
clearAllHighlights();
selectedUnit = null;
- // Switch turns
endTurn();
}
});
}
});
}
-// Check if auto-attack is possible (for units that moved next to enemies)
-function checkForAutoAttack() {
- // Not implemented in this version - all attacks are chosen by player
-}
-// Get adjacent cells
+function checkForAutoAttack() {}
function getAdjacentCells(row, col) {
var adjacent = [];
var directions = [{
r: -1,
@@ -1968,75 +929,51 @@
r: 1,
c: 1
}];
for (var i = 0; i < directions.length; i++) {
- var newRow = row + directions[i].r;
- var newCol = col + directions[i].c;
+ var newRow = row + directions[i].r,
+ newCol = col + directions[i].c;
if (newRow >= 0 && newRow < GRID_ROWS && newCol >= 0 && newCol < GRID_COLS) {
adjacent.push(grid[newRow][newCol]);
}
}
return adjacent;
}
-// Remove a unit from the game
function removeUnit(unit) {
- // Clear grid cell
grid[unit.row][unit.col].occupied = false;
grid[unit.row][unit.col].occupiedBy = null;
- // Remove from units array
var index = units.indexOf(unit);
- if (index > -1) {
- units.splice(index, 1);
- }
- // Remove from display
+ if (index > -1) units.splice(index, 1);
game.removeChild(unit);
- // Check for game over if a king was killed
if (unit.isKing) {
- if (unit.team === 'blue') {
- endGame('red');
- } else {
- endGame('blue');
- }
+ if (unit.team === 'blue') endGame('red');else endGame('blue');
}
}
-// Clear all highlights from the grid
function clearAllHighlights() {
for (var row = 0; row < GRID_ROWS; row++) {
for (var col = 0; col < GRID_COLS; col++) {
grid[row][col].clearHighlight();
}
}
}
-// End the current turn
function endTurn() {
- // Store the current state before any changes
var currentState = gameState;
if (currentState === 'playerTurn') {
- // Update state first before AI processing
gameState = 'aiTurn';
statusText.setText('AI Turn');
- // Execute AI turn with delay for better visibility
LK.setTimeout(function () {
- // Only continue AI processing if we're still in AI turn
- // This prevents state inconsistency if player somehow triggered endTurn again
if (gameState === 'aiTurn') {
- if (ai.makeMove()) {
- // AI successfully made a move, turn will be ended in the attack/move handlers
- // No state change needed here - the AI's attack/move will call endTurn() again
- } else {
- // AI couldn't make a move, switch back to player
+ if (ai.makeMove()) {} else {
gameState = 'playerTurn';
statusText.setText('Player Turn');
}
}
- }, 500); // Small delay for better user experience
+ }, 500);
} else if (currentState === 'aiTurn') {
- // Only change to player turn if we were actually in AI turn
gameState = 'playerTurn';
statusText.setText('Player Turn');
}
}
-// End the game with a winner
function endGame(winner) {
gameState = 'gameOver';
if (winner === 'blue') {
statusText.setText('You Win!');
@@ -2045,143 +982,105 @@
statusText.setText('Game Over');
LK.showGameOver();
}
}
-// Helper functions to determine critical damage relationships
function isCriticalDamage(attackerType, targetType) {
- // Knights are strong against archers
- if (attackerType === 'knight' && targetType === 'archer') {
- return true;
- }
- // Archers are strong against mages/wizards
- if (attackerType === 'archer' && targetType === 'wizard') {
- return true;
- }
- // Mages/wizards are strong against knights
- if (attackerType === 'wizard' && targetType === 'knight') {
- return true;
- }
+ if (attackerType === 'knight' && targetType === 'archer') return true;
+ if (attackerType === 'archer' && targetType === 'wizard') return true;
+ if (attackerType === 'wizard' && targetType === 'knight') return true;
return false;
}
-// Make isCriticalDamage available to the game object
game.isCriticalDamage = isCriticalDamage;
function getCriticalDamageMultiplier() {
- // Critical damage is 2x normal damage
return 2.0;
}
-// Helper functions
game.getTeamUnits = function (team) {
return units.filter(function (unit) {
return unit.team === team;
});
};
game.getKing = function (team) {
for (var i = 0; i < units.length; i++) {
- if (units[i].isKing && units[i].team === team) {
- return units[i];
- }
+ if (units[i].isKing && units[i].team === team) return units[i];
}
return null;
};
-// Expose functions to game object for access from other classes
game.selectUnit = selectUnit;
game.moveSelectedUnit = moveSelectedUnit;
game.attackCell = attackCell;
game.grid = grid;
game.gameState = gameState;
game.getAdjacentCells = getAdjacentCells;
-// Create a getter/setter for game state to ensure consistency
Object.defineProperty(game, 'gameState', {
get: function get() {
return gameState;
},
set: function set(value) {
gameState = value;
}
});
-// Function to update tutorial position
game.updateTutorialPosition = function (x, y) {
- // Update the offset vector
tutorialOffset.x = x || tutorialOffset.x;
tutorialOffset.y = y || tutorialOffset.y;
- // Update positions if tutorial is active
if (tutorialScreen && tutorialScreen.parent) {
- // Update main container position
tutorialScreen.scrollContainer.x = 1024 + tutorialOffset.x;
tutorialScreen.scrollContainer.y = -tutorialScreen.scrollY + tutorialOffset.y;
- // Update back button position
- var backButton = tutorialScreen.children[tutorialScreen.children.length - 2]; // Back button is second to last child
+ var backButton = tutorialScreen.children[tutorialScreen.children.length - 2];
backButton.x = 200 + tutorialOffset.x;
backButton.y = 2500 + tutorialOffset.y;
- // Update scroll indicator position
- var scrollIndicator = tutorialScreen.children[tutorialScreen.children.length - 1]; // Scroll indicator is last child
+ var scrollIndicator = tutorialScreen.children[tutorialScreen.children.length - 1];
scrollIndicator.x = 1950 + tutorialOffset.x;
scrollIndicator.y = 1366 + tutorialOffset.y;
}
};
-// Screen management functions
game.showTitleScreen = function () {
- // Clear any existing game elements
game.removeAllGameElements();
- // Show title screen
game.addChild(titleScreen);
game.removeChild(tutorialScreen);
game.removeChild(settingsScreen);
- // Hide status text during main menu
statusText.visible = false;
- // Set game state
gameState = 'mainMenu';
- // Animate title to top third of screen
var logo = titleScreen.children[0];
var titleText = titleScreen.children[1];
- // Animate logo
tween(logo, {
y: -500
}, {
duration: 800,
easing: tween.elasticOut
});
- // Animate title text
tween(titleText, {
y: 800
}, {
duration: 800,
easing: tween.elasticOut
});
};
game.showTutorial = function () {
- // Show tutorial screen
game.removeChild(titleScreen);
game.addChild(tutorialScreen);
game.removeChild(settingsScreen);
- // Set game state
gameState = 'tutorial';
};
game.showSettings = function () {
- // Show settings screen
game.removeChild(titleScreen);
game.removeChild(tutorialScreen);
game.addChild(settingsScreen);
- // Set game state
gameState = 'settings';
};
game.startGame = function () {
- // Clear screens
game.removeChild(titleScreen);
game.removeChild(tutorialScreen);
game.removeChild(settingsScreen);
- // Initialize the game grid
for (var row = 0; row < GRID_ROWS; row++) {
grid[row] = [];
for (var col = 0; col < GRID_COLS; col++) {
var cell = new GridCell();
cell.row = row;
cell.col = col;
cell.x = GRID_PADDING_X + col * CELL_SIZE + CELL_SIZE / 2;
cell.y = GRID_PADDING_Y + row * CELL_SIZE + CELL_SIZE / 2;
- // Alternate cell colors
if ((row + col) % 2 === 0) {
- cell.removeChild(cell.children[0]); // Remove default graphic
+ cell.removeChild(cell.children[0]);
cell.attachAsset('grid_cell_dark', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.5
@@ -2190,32 +1089,23 @@
grid[row][col] = cell;
game.addChild(cell);
}
}
- // Create units
createUnits();
- // Show status text during gameplay
statusText.visible = true;
statusText.setText('Player Turn');
- // Set game state
gameState = 'playerTurn';
};
game.removeAllGameElements = function () {
- // Remove grid cells if they exist
for (var row = 0; row < grid.length; row++) {
for (var col = 0; col < grid[row].length; col++) {
- if (grid[row][col]) {
- game.removeChild(grid[row][col]);
- }
+ if (grid[row][col]) game.removeChild(grid[row][col]);
}
}
- // Remove units
for (var i = 0; i < units.length; i++) {
game.removeChild(units[i]);
}
- // Reset game variables
grid = [];
units = [];
selectedUnit = null;
};
-// Initialize game
initializeGame();
\ No newline at end of file
top view
make it have red-ish clothes
Make it seen from behind top view
make it seen from behind top view
make it just a grass field, and make it from 3 times far away
Create a logo for this game based on this description: Title: "Tactical Kings: Battle of Champions" A fantasy-themed, chess-inspired strategy game where players control unique units with predefined attack zones. Victory comes from eliminating the opponent’s King by strategically positioning characters on a 5x10 grid.. In-Game asset. 2d. High contrast. No shadows
make it wear more blue ish colors
make it from top view
paint the word silver
top view, seeing the back of the character
top down view, do not cut any elements off screen
Make it seen from his back, do not cut any elements off screen