User prompt
it doesnt let the player play after the first turn, from the second turn and on it shows only the next turn ui and doesnt let the player play
User prompt
Make it turn base, the Ai cant continuosly play
User prompt
Change the attack zone for the mage, it can only attack characters that is on tile around its attack tile
User prompt
The position of the characters in the blue team is inverted. THE line where tha king is should be below the line of the warriors and knights
User prompt
change the characters positioning, it should be Red: Archer, Mage, King, Mage, Archer Kinght, warrior, warrior, warrior, Knight Blue: Kinght, warrior, warrior, warrior, Knight Archer, Mage, King, Mage, Archer
User prompt
change the postition fo the characters for both teams. It should be like: blue team ex: Archer, Mage, King, Mage, Archer Knight, warrior, warrior, warrior, knight
User prompt
change the postition fo the characters for both teams. It should be like: blue team ex: Knight, warrior, warrior, warrior, knight Archer, Mage, King, Mage, Archer
User prompt
increase the size, make the whole arena fit to the screen
User prompt
Increase the size of everything, so that the board fits the screen ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Create game
Code edit (1 edits merged)
Please save this source code
User prompt
Tactical Kings: Battle of Champions
Initial prompt
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. Core Mechanics: Turn-Based Gameplay: Players take turns moving one character at a time, with automatic attacks occurring after movement. Pre-Calculated Attacks: Before moving, players see highlighted attack zones to plan the best positioning. Character Roles & Counters: Spear Knights → Strong melee attacks, move straight or sideways (1-3 tiles). Archers → Long-range (8 tiles forward), move sideways freely but only one tile forward if moving forward. Mages → Cast area spells 6 tiles ahead, damaging all surrounding enemies. Tank → Instant-kill attack (1 tile forward), slow movement (only 1 tile per turn). King → Moves freely like a chess queen, but only attacks 1 tile forward. AI Strategy: Simple pattern-following—AI moves towards optimal attack positions without complex decision trees. Minimal Animations: Basic sprite interpolation for movement, slight grow and shrink for idle, and a sprite change for attacks. Win Condition: Eliminate the opponent's King—no timers or alternative victory methods.
/**** * Classes ****/ var AIPlayer = Container.expand(function () { var self = Container.call(this); self.makeMove = function () { var units = game.getTeamUnits('red'); var moveFound = false; // 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; }); if (kingAttack) { game.selectUnit(unit); game.attackCell(game.grid[kingAttack.row][kingAttack.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; 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 (dist < closestDistance) { closestUnit = unit; closestDistance = dist; } } } if (closestUnit) { var bestMove = null; var 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)); if (moveScore > bestMoveScore) { bestMove = move; bestMoveScore = moveScore; } } if (bestMove) { game.selectUnit(closestUnit); game.moveSelectedUnit(bestMove.row, bestMove.col); return true; } } } // Last resort: random move with random unit var movableUnits = units.filter(function (unit) { return unit.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; // No move possible }; 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); } self.highlighted = true; self.highlightType = type; if (type === 'move') { self.highlightAsset = self.attachAsset('highlight_move', { 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) { self.removeChild(self.highlightAsset); self.highlightAsset = null; } self.highlighted = false; self.highlightType = null; }; // Event handlers self.down = function (x, y, obj) { if (game.gameState === 'playerTurn') { game.handleCellClick(self); } }; 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; // 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'; var assetId = type + '_' + team; self.unitGraphic = self.attachAsset(assetId, { anchorX: 0.5, anchorY: 0.5 }); 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) { // Cast area spells 6 tiles ahead var forwardLimit = self.team === 'blue' ? self.row - 6 : self.row + 6; var inRange = false; if (self.team === 'blue') { inRange = targetRow >= forwardLimit && targetRow < self.row; } else { inRange = targetRow <= forwardLimit && targetRow > self.row; } return inRange; }; // 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 1 tile in any direction return rowDiff <= 1 && colDiff <= 1 && !(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 - 1 && targetCol === self.col; } else { return targetRow === self.row + 1 && 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 3 tiles return rowDiff === 0 && colDiff > 0 && colDiff <= 3 || colDiff === 0 && rowDiff > 0 && rowDiff <= 3; }; // Override attack validation self.canAttack = function (targetRow, targetCol) { // Same as movement - can attack in movement range return self.canMoveTo(targetRow, targetCol); }; return self; }); var King = Unit.expand(function () { var self = Unit.call(this); // Override movement validation self.canMoveTo = function (targetRow, targetCol) { // King moves like a chess queen but limited distance var rowDiff = Math.abs(targetRow - self.row); var colDiff = Math.abs(targetCol - self.col); // Can move in any direction but maximum 1 space return rowDiff <= 1 && colDiff <= 1 && !(rowDiff === 0 && colDiff === 0); }; // Override attack validation self.canAttack = function (targetRow, targetCol) { // King only attacks 1 tile forward based on team direction var forwardRow = self.team === 'blue' ? self.row - 1 : self.row + 1; 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 one tile forward if (self.team === 'blue') { return colDiff > 0 && rowDiff === 0 || // sideways targetRow === self.row - 1 && colDiff === 0; // one forward } else { return colDiff > 0 && rowDiff === 0 || // sideways targetRow === self.row + 1 && colDiff === 0; // one forward } }; // Override attack validation self.canAttack = function (targetRow, targetCol) { // Can attack up to 8 tiles ahead if (self.team === 'blue') { return targetCol === self.col && targetRow < self.row && self.row - targetRow <= 8; } else { return targetCol === self.col && targetRow > self.row && targetRow - self.row <= 8; } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // Game constants var GRID_ROWS = 10; var GRID_COLS = 5; var CELL_SIZE = 130; 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 = 'playerTurn'; // playerTurn, aiTurn, gameOver var ai = new AIPlayer(); var statusText = new Text2('Player Turn', { size: 60, fill: 0xFFFFFF }); // Initialize the game board function initializeGame() { // Create 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.attachAsset('grid_cell_dark', { anchorX: 0.5, anchorY: 0.5, alpha: 0.5 }); } grid[row][col] = cell; game.addChild(cell); } } // Create units for both teams createUnits(); // Add status text statusText.anchor.set(0.5, 0); statusText.x = 2048 / 2; statusText.y = 50; LK.gui.top.addChild(statusText); } // Create all units for both teams function createUnits() { // Blue team (player) - bottom of the board createUnit('king', 'blue', 9, 2); createUnit('knight', 'blue', 8, 1); createUnit('knight', 'blue', 8, 3); createUnit('archer', 'blue', 8, 0); createUnit('archer', 'blue', 8, 4); createUnit('wizard', 'blue', 9, 0); createUnit('wizard', 'blue', 9, 4); createUnit('warrior', 'blue', 9, 1); createUnit('warrior', 'blue', 9, 3); // Red team (AI) - top of the board createUnit('king', 'red', 0, 2); createUnit('knight', 'red', 1, 1); createUnit('knight', 'red', 1, 3); createUnit('archer', 'red', 1, 0); createUnit('archer', 'red', 1, 4); createUnit('wizard', 'red', 0, 0); createUnit('wizard', 'red', 0, 4); createUnit('warrior', 'red', 0, 1); createUnit('warrior', 'red', 0, 3); } // 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; 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; } // Position unit unit.x = grid[row][col].x; unit.y = grid[row][col].y; unit.unitGraphic.alpha = 0.8; // 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 (gameState === 'playerTurn') { selectUnit(unit); } }; } return unit; } // Handle cell click game.handleCellClick = function (cell) { if (!selectedUnit) 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); } }; // 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 (selectedUnit) { selectedUnit.deselect(); clearAllHighlights(); } // Select new unit selectedUnit = unit; selectedUnit.select(); // Highlight cell under selected unit grid[unit.row][unit.col].highlight('selected'); // Highlight possible moves var possibleMoves = unit.getPossibleMoves(grid); for (var i = 0; i < possibleMoves.length; i++) { var move = possibleMoves[i]; grid[move.row][move.col].highlight('move'); } // Highlight possible attacks var possibleAttacks = unit.getPossibleAttacks(grid); for (var i = 0; i < possibleAttacks.length; i++) { var attack = possibleAttacks[i]; grid[attack.row][attack.col].highlight('attack'); } } // Move selected unit to new position function moveSelectedUnit(targetRow, targetCol) { if (!selectedUnit) return; // Update grid occupation grid[selectedUnit.row][selectedUnit.col].occupied = false; grid[selectedUnit.row][selectedUnit.col].occupiedBy = null; // Move unit selectedUnit.moveTo(targetRow, targetCol); selectedUnit.x = grid[targetRow][targetCol].x; selectedUnit.y = grid[targetRow][targetCol].y; // 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; var targetUnit = cell.occupiedBy; // Perform attack if (selectedUnit.hasInstantKill || targetUnit.isKing) { // Instant kill or attacking king always results in death removeUnit(targetUnit); } else if (selectedUnit.isAreaAttacker) { // Area attack affects target and adjacent units of opposite team var adjacentCells = getAdjacentCells(cell.row, cell.col); removeUnit(targetUnit); for (var i = 0; i < adjacentCells.length; i++) { var adjCell = adjacentCells[i]; if (adjCell.occupied && adjCell.occupiedBy.team !== selectedUnit.team) { removeUnit(adjCell.occupiedBy); } } } else { // Normal attack 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 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; var 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 game.removeChild(unit); // Check for game over if a king was killed if (unit.isKing) { 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() { if (gameState === 'playerTurn') { gameState = 'aiTurn'; statusText.setText('AI Turn'); // Small delay before AI makes its move LK.setTimeout(function () { ai.makeMove(); // Switch back to player turn gameState = 'playerTurn'; statusText.setText('Player Turn'); }, 500); } else if (gameState === 'aiTurn') { gameState = 'playerTurn'; statusText.setText('Player Turn'); } } // End the game with a winner function endGame(winner) { gameState = 'gameOver'; if (winner === 'blue') { statusText.setText('You Win!'); LK.showYouWin(); } else { statusText.setText('Game Over'); LK.showGameOver(); } } // 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]; } } 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; // Initialize game initializeGame();
===================================================================
--- original.js
+++ change.js
@@ -1,618 +1,664 @@
/****
-* Plugins
-****/
-var tween = LK.import("@upit/tween.v1");
-var storage = LK.import("@upit/storage.v1");
-
-/****
* Classes
****/
-var GridCell = Container.expand(function () {
+var AIPlayer = Container.expand(function () {
var self = Container.call(this);
- self.initialize = function (row, col, isDark) {
- self.row = row;
- self.col = col;
- self.isDark = isDark;
- var cell = self.attachAsset(isDark ? 'grid_cell_dark' : 'grid_cell', {
- anchorX: 0.5,
- anchorY: 0.5,
- alpha: 0.8
+ self.makeMove = function () {
+ var units = game.getTeamUnits('red');
+ var moveFound = false;
+ // 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;
+ });
+ if (kingAttack) {
+ game.selectUnit(unit);
+ game.attackCell(game.grid[kingAttack.row][kingAttack.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;
+ 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 (dist < closestDistance) {
+ closestUnit = unit;
+ closestDistance = dist;
+ }
+ }
+ }
+ if (closestUnit) {
+ var bestMove = null;
+ var 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));
+ if (moveScore > bestMoveScore) {
+ bestMove = move;
+ bestMoveScore = moveScore;
+ }
+ }
+ if (bestMove) {
+ game.selectUnit(closestUnit);
+ game.moveSelectedUnit(bestMove.row, bestMove.col);
+ return true;
+ }
+ }
+ }
+ // Last resort: random move with random unit
+ var movableUnits = units.filter(function (unit) {
+ return unit.getPossibleMoves(game.grid).length > 0;
});
- self.highlight = null;
- self.character = null;
- self.isMovable = false;
- self.isAttackable = false;
+ 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; // No move possible
};
- self.setHighlight = function (type) {
- if (self.highlight) {
- self.removeChild(self.highlight);
- self.highlight = null;
+ 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 (type) {
- self.highlight = self.attachAsset('highlight_' + type, {
+ self.highlighted = true;
+ self.highlightType = type;
+ if (type === 'move') {
+ self.highlightAsset = self.attachAsset('highlight_move', {
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.setCharacter = function (character) {
- self.character = character;
+ self.clearHighlight = function () {
+ if (self.highlightAsset) {
+ self.removeChild(self.highlightAsset);
+ self.highlightAsset = null;
+ }
+ self.highlighted = false;
+ self.highlightType = null;
};
+ // Event handlers
self.down = function (x, y, obj) {
- if (gameState.currentPhase) {
- gameState.handleCellClick(self);
+ if (game.gameState === 'playerTurn') {
+ game.handleCellClick(self);
}
};
return self;
});
var Unit = Container.expand(function () {
var self = Container.call(this);
- self.initialize = function (type, team, row, col) {
+ // Unit properties
+ self.type = "";
+ self.team = "";
+ self.row = 0;
+ self.col = 0;
+ self.isKing = false;
+ self.alive = true;
+ self.selected = false;
+ // Initialize with type and team
+ self.init = function (type, team, row, col) {
self.type = type;
self.team = team;
self.row = row;
self.col = col;
- var asset = self.attachAsset(type + '_' + team, {
+ self.isKing = type === 'king';
+ var assetId = type + '_' + team;
+ self.unitGraphic = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
- // Set up movement and attack patterns based on unit type
- self.setupPatterns();
+ return self;
};
- self.setupPatterns = function () {
- // Define movement and attack patterns for different unit types
- switch (self.type) {
- case 'king':
- self.movePattern = [{
- row: -1,
- col: -1
- }, {
- row: -1,
- col: 0
- }, {
- row: -1,
- col: 1
- }, {
- row: 0,
- col: -1
- }, {
- row: 0,
- col: 1
- }, {
- row: 1,
- col: -1
- }, {
- row: 1,
- col: 0
- }, {
- row: 1,
- col: 1
- }];
- self.attackPattern = [{
- row: -1,
- col: -1
- }, {
- row: -1,
- col: 0
- }, {
- row: -1,
- col: 1
- }, {
- row: 0,
- col: -1
- }, {
- row: 0,
- col: 1
- }, {
- row: 1,
- col: -1
- }, {
- row: 1,
- col: 0
- }, {
- row: 1,
- col: 1
- }];
- break;
- case 'knight':
- self.movePattern = [{
- row: -2,
- col: -1
- }, {
- row: -2,
- col: 1
- }, {
- row: -1,
- col: -2
- }, {
- row: -1,
- col: 2
- }, {
- row: 1,
- col: -2
- }, {
- row: 1,
- col: 2
- }, {
- row: 2,
- col: -1
- }, {
- row: 2,
- col: 1
- }];
- self.attackPattern = [{
- row: -1,
- col: -1
- }, {
- row: -1,
- col: 1
- }, {
- row: 1,
- col: -1
- }, {
- row: 1,
- col: 1
- }];
- break;
- case 'wizard':
- self.movePattern = [{
- row: -1,
- col: 0
- }, {
- row: 0,
- col: -1
- }, {
- row: 0,
- col: 1
- }, {
- row: 1,
- col: 0
- }];
- self.attackPattern = [{
- row: -2,
- col: -2
- }, {
- row: -2,
- col: 0
- }, {
- row: -2,
- col: 2
- }, {
- row: 0,
- col: -2
- }, {
- row: 0,
- col: 2
- }, {
- row: 2,
- col: -2
- }, {
- row: 2,
- col: 0
- }, {
- row: 2,
- col: 2
- }];
- break;
- case 'archer':
- self.movePattern = [{
- row: -1,
- col: 0
- }, {
- row: 0,
- col: -1
- }, {
- row: 0,
- col: 1
- }, {
- row: 1,
- col: 0
- }];
- self.attackPattern = [{
- row: -3,
- col: 0
- }, {
- row: -2,
- col: 0
- }, {
- row: -1,
- col: 0
- }, {
- row: 0,
- col: -3
- }, {
- row: 0,
- col: -2
- }, {
- row: 0,
- col: -1
- }, {
- row: 0,
- col: 1
- }, {
- row: 0,
- col: 2
- }, {
- row: 0,
- col: 3
- }, {
- row: 1,
- col: 0
- }, {
- row: 2,
- col: 0
- }, {
- row: 3,
- col: 0
- }];
- break;
- case 'warrior':
- self.movePattern = [{
- row: -1,
- col: 0
- }, {
- row: 0,
- col: -1
- }, {
- row: 0,
- col: 1
- }, {
- row: 1,
- col: 0
- }, {
- row: -1,
- col: -1
- }, {
- row: -1,
- col: 1
- }, {
- row: 1,
- col: -1
- }, {
- row: 1,
- col: 1
- }];
- self.attackPattern = [{
- row: -1,
- col: 0
- }, {
- row: 0,
- col: -1
- }, {
- row: 0,
- col: 1
- }, {
- row: 1,
- col: 0
- }];
- break;
- default:
- self.movePattern = [];
- self.attackPattern = [];
+ // 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;
};
- self.moveTo = function (row, col) {
- self.row = row;
- self.col = col;
+ // 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;
};
- self.down = function (x, y, obj) {
- if (gameState.currentPhase === "select" && self.team === gameState.currentPlayer) {
- gameState.selectUnit(self);
- LK.getSound('select').play();
+ // 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) {
+ // Cast area spells 6 tiles ahead
+ var forwardLimit = self.team === 'blue' ? self.row - 6 : self.row + 6;
+ var inRange = false;
+ if (self.team === 'blue') {
+ inRange = targetRow >= forwardLimit && targetRow < self.row;
+ } else {
+ inRange = targetRow <= forwardLimit && targetRow > self.row;
}
+ return inRange;
};
+ // 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 1 tile in any direction
+ return rowDiff <= 1 && colDiff <= 1 && !(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 - 1 && targetCol === self.col;
+ } else {
+ return targetRow === self.row + 1 && 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 3 tiles
+ return rowDiff === 0 && colDiff > 0 && colDiff <= 3 || colDiff === 0 && rowDiff > 0 && rowDiff <= 3;
+ };
+ // Override attack validation
+ self.canAttack = function (targetRow, targetCol) {
+ // Same as movement - can attack in movement range
+ return self.canMoveTo(targetRow, targetCol);
+ };
+ return self;
+});
+var King = Unit.expand(function () {
+ var self = Unit.call(this);
+ // Override movement validation
+ self.canMoveTo = function (targetRow, targetCol) {
+ // King moves like a chess queen but limited distance
+ var rowDiff = Math.abs(targetRow - self.row);
+ var colDiff = Math.abs(targetCol - self.col);
+ // Can move in any direction but maximum 1 space
+ return rowDiff <= 1 && colDiff <= 1 && !(rowDiff === 0 && colDiff === 0);
+ };
+ // Override attack validation
+ self.canAttack = function (targetRow, targetCol) {
+ // King only attacks 1 tile forward based on team direction
+ var forwardRow = self.team === 'blue' ? self.row - 1 : self.row + 1;
+ 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 one tile forward
+ if (self.team === 'blue') {
+ return colDiff > 0 && rowDiff === 0 ||
+ // sideways
+ targetRow === self.row - 1 && colDiff === 0; // one forward
+ } else {
+ return colDiff > 0 && rowDiff === 0 ||
+ // sideways
+ targetRow === self.row + 1 && colDiff === 0; // one forward
+ }
+ };
+ // Override attack validation
+ self.canAttack = function (targetRow, targetCol) {
+ // Can attack up to 8 tiles ahead
+ if (self.team === 'blue') {
+ return targetCol === self.col && targetRow < self.row && self.row - targetRow <= 8;
+ } else {
+ return targetCol === self.col && targetRow > self.row && targetRow - self.row <= 8;
+ }
+ };
+ return self;
+});
/****
* Initialize Game
****/
var game = new LK.Game({
- backgroundColor: 0x2a623d
+ backgroundColor: 0x000000
});
/****
* Game Code
****/
-// Constants
+// Game constants
var GRID_ROWS = 10;
var GRID_COLS = 5;
var CELL_SIZE = 130;
-var GRID_WIDTH = GRID_COLS * CELL_SIZE;
-var GRID_HEIGHT = GRID_ROWS * CELL_SIZE;
-// Game state
-var gameState = {
- grid: [],
- units: [],
- selectedUnit: null,
- currentPlayer: "blue",
- // blue or red
- currentPhase: null,
- // select, move, attack
- turnCount: 0,
- initialize: function initialize() {
- // Set up game grid
- this.createGrid();
- // Create initial units
- this.createUnits();
- // Start the game
- this.startGame();
- },
- createGrid: function createGrid() {
- this.gridContainer = new Container();
- game.addChild(this.gridContainer);
- // Center the grid
- this.gridContainer.x = (2048 - GRID_WIDTH) / 2;
- this.gridContainer.y = (2732 - GRID_HEIGHT) / 2;
- // Create grid cells
- for (var row = 0; row < GRID_ROWS; row++) {
- this.grid[row] = [];
- for (var col = 0; col < GRID_COLS; col++) {
- var isDark = (row + col) % 2 === 1;
- var cell = new GridCell();
- cell.initialize(row, col, isDark);
- cell.x = col * CELL_SIZE + CELL_SIZE / 2;
- cell.y = row * CELL_SIZE + CELL_SIZE / 2;
- this.gridContainer.addChild(cell);
- this.grid[row][col] = cell;
+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 = 'playerTurn'; // playerTurn, aiTurn, gameOver
+var ai = new AIPlayer();
+var statusText = new Text2('Player Turn', {
+ size: 60,
+ fill: 0xFFFFFF
+});
+// Initialize the game board
+function initializeGame() {
+ // Create 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.attachAsset('grid_cell_dark', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ alpha: 0.5
+ });
}
+ grid[row][col] = cell;
+ game.addChild(cell);
}
- },
- createUnits: function createUnits() {
- // Create blue team units (bottom)
- this.createUnit('king', 'blue', 9, 2);
- this.createUnit('knight', 'blue', 9, 1);
- this.createUnit('knight', 'blue', 9, 3);
- this.createUnit('wizard', 'blue', 9, 0);
- this.createUnit('wizard', 'blue', 9, 4);
- this.createUnit('warrior', 'blue', 8, 1);
- this.createUnit('warrior', 'blue', 8, 3);
- this.createUnit('archer', 'blue', 8, 0);
- this.createUnit('archer', 'blue', 8, 2);
- this.createUnit('archer', 'blue', 8, 4);
- // Create red team units (top)
- this.createUnit('king', 'red', 0, 2);
- this.createUnit('knight', 'red', 0, 1);
- this.createUnit('knight', 'red', 0, 3);
- this.createUnit('wizard', 'red', 0, 0);
- this.createUnit('wizard', 'red', 0, 4);
- this.createUnit('warrior', 'red', 1, 1);
- this.createUnit('warrior', 'red', 1, 3);
- this.createUnit('archer', 'red', 1, 0);
- this.createUnit('archer', 'red', 1, 2);
- this.createUnit('archer', 'red', 1, 4);
- },
- createUnit: function createUnit(type, team, row, col) {
- var unit = new Unit();
- unit.initialize(type, team, row, col);
- var cell = this.grid[row][col];
- cell.setCharacter(unit);
- // Position unit on the cell
- unit.x = cell.x;
- unit.y = cell.y;
- this.gridContainer.addChild(unit);
- this.units.push(unit);
- return unit;
- },
- startGame: function startGame() {
- this.createUI();
- this.startTurn();
- LK.playMusic('bgm');
- },
- createUI: function createUI() {
- // Create turn indicator
- this.turnText = new Text2("BLUE'S TURN", {
- size: 80,
- fill: 0x0000FF
- });
- this.turnText.anchor.set(0.5, 0);
- this.turnText.x = 2048 / 2;
- this.turnText.y = 50;
- LK.gui.addChild(this.turnText);
- // Create phase indicator
- this.phaseText = new Text2("SELECT UNIT", {
- size: 60,
- fill: 0xFFFFFF
- });
- this.phaseText.anchor.set(0.5, 0);
- this.phaseText.x = 2048 / 2;
- this.phaseText.y = 140;
- LK.gui.addChild(this.phaseText);
- // Create end turn button
- this.endTurnButton = new Container();
- var buttonBackground = LK.getAsset('grid_cell', {
- anchorX: 0.5,
- anchorY: 0.5,
- width: 300,
- height: 80,
- tint: 0x888888
- });
- this.endTurnButton.addChild(buttonBackground);
- var buttonText = new Text2("END TURN", {
- size: 40,
- fill: 0xFFFFFF
- });
- buttonText.anchor.set(0.5, 0.5);
- this.endTurnButton.addChild(buttonText);
- this.endTurnButton.x = 2048 - 200;
- this.endTurnButton.y = 100;
- LK.gui.addChild(this.endTurnButton);
- this.endTurnButton.interactive = true;
- this.endTurnButton.down = function () {
- if (gameState.currentPhase) {
- gameState.endTurn();
+ }
+ // Create units for both teams
+ createUnits();
+ // Add status text
+ statusText.anchor.set(0.5, 0);
+ statusText.x = 2048 / 2;
+ statusText.y = 50;
+ LK.gui.top.addChild(statusText);
+}
+// Create all units for both teams
+function createUnits() {
+ // Blue team (player) - bottom of the board
+ createUnit('king', 'blue', 9, 2);
+ createUnit('knight', 'blue', 8, 1);
+ createUnit('knight', 'blue', 8, 3);
+ createUnit('archer', 'blue', 8, 0);
+ createUnit('archer', 'blue', 8, 4);
+ createUnit('wizard', 'blue', 9, 0);
+ createUnit('wizard', 'blue', 9, 4);
+ createUnit('warrior', 'blue', 9, 1);
+ createUnit('warrior', 'blue', 9, 3);
+ // Red team (AI) - top of the board
+ createUnit('king', 'red', 0, 2);
+ createUnit('knight', 'red', 1, 1);
+ createUnit('knight', 'red', 1, 3);
+ createUnit('archer', 'red', 1, 0);
+ createUnit('archer', 'red', 1, 4);
+ createUnit('wizard', 'red', 0, 0);
+ createUnit('wizard', 'red', 0, 4);
+ createUnit('warrior', 'red', 0, 1);
+ createUnit('warrior', 'red', 0, 3);
+}
+// 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;
+ 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;
+ }
+ // Position unit
+ unit.x = grid[row][col].x;
+ unit.y = grid[row][col].y;
+ unit.unitGraphic.alpha = 0.8;
+ // 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 (gameState === 'playerTurn') {
+ selectUnit(unit);
}
};
- },
- startTurn: function startTurn() {
- this.currentPhase = "select";
- this.turnCount++;
- // Update UI
- this.turnText.setText(this.currentPlayer.toUpperCase() + "'S TURN");
- this.turnText.style.fill = this.currentPlayer === "blue" ? "#0000ff" : "#ff0000";
- this.phaseText.setText("SELECT UNIT");
- // Reset all highlights
- this.clearHighlights();
- },
- selectUnit: function selectUnit(unit) {
- if (this.currentPhase !== "select" || unit.team !== this.currentPlayer) {
- return;
- }
- // Deselect previously selected unit
- if (this.selectedUnit) {
- var oldCell = this.getCellAt(this.selectedUnit.row, this.selectedUnit.col);
- oldCell.setHighlight(null);
- }
- this.selectedUnit = unit;
- // Highlight selected unit
- var selectedCell = this.getCellAt(unit.row, unit.col);
- selectedCell.setHighlight("selected");
- // Show movement options
- this.showMoveOptions();
- // Update phase
- this.currentPhase = "move";
- this.phaseText.setText("MOVE UNIT");
- },
- showMoveOptions: function showMoveOptions() {
- this.clearHighlights("selected");
- var unit = this.selectedUnit;
- if (!unit) return;
- // Highlight possible moves
- for (var i = 0; i < unit.movePattern.length; i++) {
- var move = unit.movePattern[i];
- var newRow = unit.row + move.row;
- var newCol = unit.col + move.col;
- // Check if the new position is within the grid and empty
- if (this.isValidPosition(newRow, newCol)) {
- var cell = this.getCellAt(newRow, newCol);
- if (!cell.character) {
- cell.setHighlight("move");
- cell.isMovable = true;
- }
+ }
+ return unit;
+}
+// Handle cell click
+game.handleCellClick = function (cell) {
+ if (!selectedUnit) 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);
+ }
+};
+// 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 (selectedUnit) {
+ selectedUnit.deselect();
+ clearAllHighlights();
+ }
+ // Select new unit
+ selectedUnit = unit;
+ selectedUnit.select();
+ // Highlight cell under selected unit
+ grid[unit.row][unit.col].highlight('selected');
+ // Highlight possible moves
+ var possibleMoves = unit.getPossibleMoves(grid);
+ for (var i = 0; i < possibleMoves.length; i++) {
+ var move = possibleMoves[i];
+ grid[move.row][move.col].highlight('move');
+ }
+ // Highlight possible attacks
+ var possibleAttacks = unit.getPossibleAttacks(grid);
+ for (var i = 0; i < possibleAttacks.length; i++) {
+ var attack = possibleAttacks[i];
+ grid[attack.row][attack.col].highlight('attack');
+ }
+}
+// Move selected unit to new position
+function moveSelectedUnit(targetRow, targetCol) {
+ if (!selectedUnit) return;
+ // Update grid occupation
+ grid[selectedUnit.row][selectedUnit.col].occupied = false;
+ grid[selectedUnit.row][selectedUnit.col].occupiedBy = null;
+ // Move unit
+ selectedUnit.moveTo(targetRow, targetCol);
+ selectedUnit.x = grid[targetRow][targetCol].x;
+ selectedUnit.y = grid[targetRow][targetCol].y;
+ // 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;
+ var targetUnit = cell.occupiedBy;
+ // Perform attack
+ if (selectedUnit.hasInstantKill || targetUnit.isKing) {
+ // Instant kill or attacking king always results in death
+ removeUnit(targetUnit);
+ } else if (selectedUnit.isAreaAttacker) {
+ // Area attack affects target and adjacent units of opposite team
+ var adjacentCells = getAdjacentCells(cell.row, cell.col);
+ removeUnit(targetUnit);
+ for (var i = 0; i < adjacentCells.length; i++) {
+ var adjCell = adjacentCells[i];
+ if (adjCell.occupied && adjCell.occupiedBy.team !== selectedUnit.team) {
+ removeUnit(adjCell.occupiedBy);
}
}
- },
- showAttackOptions: function showAttackOptions() {
- this.clearHighlights();
- var unit = this.selectedUnit;
- if (!unit) return;
- // Highlight the unit
- var selectedCell = this.getCellAt(unit.row, unit.col);
- selectedCell.setHighlight("selected");
- // Highlight possible attacks
- for (var i = 0; i < unit.attackPattern.length; i++) {
- var attack = unit.attackPattern[i];
- var targetRow = unit.row + attack.row;
- var targetCol = unit.col + attack.col;
- // Check if the target position is within the grid
- if (this.isValidPosition(targetRow, targetCol)) {
- var cell = this.getCellAt(targetRow, targetCol);
- if (cell.character && cell.character.team !== unit.team) {
- cell.setHighlight("attack");
- cell.isAttackable = true;
- }
- }
+ } else {
+ // Normal attack
+ 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 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;
+ var newCol = col + directions[i].c;
+ if (newRow >= 0 && newRow < GRID_ROWS && newCol >= 0 && newCol < GRID_COLS) {
+ adjacent.push(grid[newRow][newCol]);
}
- },
- handleCellClick: function handleCellClick(cell) {
- if (this.currentPhase === "move" && cell.isMovable) {
- this.moveUnit(cell);
- } else if (this.currentPhase === "attack" && cell.isAttackable) {
- this.attackUnit(cell);
+ }
+ 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
+ game.removeChild(unit);
+ // Check for game over if a king was killed
+ if (unit.isKing) {
+ if (unit.team === 'blue') {
+ endGame('red');
+ } else {
+ endGame('blue');
}
- },
- moveUnit: function moveUnit(targetCell) {
- if (!this.selectedUnit) return;
- // Get current cell
- var currentCell = this.getCellAt(this.selectedUnit.row, this.selectedUnit.col);
- // Update unit position
- this.selectedUnit.moveTo(targetCell.row, targetCell.col);
- // Update cell references
- currentCell.setCharacter(null);
- targetCell.setCharacter(this.selectedUnit);
- // Animate movement
- tween(this.selectedUnit, {
- x: targetCell.x,
- y: targetCell.y
- }, {
- duration: 300,
- onFinish: function onFinish() {
- gameState.currentPhase = "attack";
- gameState.phaseText.setText("ATTACK OR END TURN");
- gameState.showAttackOptions();
- LK.getSound('move').play();
- }
- });
- },
- attackUnit: function attackUnit(targetCell) {
- var target = targetCell.character;
- if (!target) return;
- // Play attack sound
- LK.getSound('attack').play();
- // Flash target
- LK.effects.flashObject(target, 0xff0000, 500);
- // Remove target unit
- this.removeUnit(target);
- // Check if game over (king eliminated)
- if (target.type === 'king') {
- this.gameOver(this.currentPlayer);
- return;
+ }
+}
+// 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 turn after attack
- this.endTurn();
- },
- removeUnit: function removeUnit(unit) {
- // Remove from grid cell
- var cell = this.getCellAt(unit.row, unit.col);
- cell.setCharacter(null);
- // Remove from display
- this.gridContainer.removeChild(unit);
- // Remove from units array
- var index = this.units.indexOf(unit);
- if (index !== -1) {
- this.units.splice(index, 1);
- }
- },
- endTurn: function endTurn() {
- this.selectedUnit = null;
- this.clearHighlights();
- // Switch players
- this.currentPlayer = this.currentPlayer === "blue" ? "red" : "blue";
- // Start new turn
- this.startTurn();
- },
- gameOver: function gameOver(winner) {
- // Update score
- LK.setScore(winner === "blue" ? 1 : 2);
- // Show game over screen
+ }
+}
+// End the current turn
+function endTurn() {
+ if (gameState === 'playerTurn') {
+ gameState = 'aiTurn';
+ statusText.setText('AI Turn');
+ // Small delay before AI makes its move
+ LK.setTimeout(function () {
+ ai.makeMove();
+ // Switch back to player turn
+ gameState = 'playerTurn';
+ statusText.setText('Player Turn');
+ }, 500);
+ } else if (gameState === 'aiTurn') {
+ gameState = 'playerTurn';
+ statusText.setText('Player Turn');
+ }
+}
+// End the game with a winner
+function endGame(winner) {
+ gameState = 'gameOver';
+ if (winner === 'blue') {
+ statusText.setText('You Win!');
LK.showYouWin();
- },
- clearHighlights: function clearHighlights(except) {
- for (var row = 0; row < GRID_ROWS; row++) {
- for (var col = 0; col < GRID_COLS; col++) {
- var cell = this.grid[row][col];
- if (!except || cell.highlight !== except) {
- cell.setHighlight(null);
- cell.isMovable = false;
- cell.isAttackable = false;
- }
- }
+ } else {
+ statusText.setText('Game Over');
+ LK.showGameOver();
+ }
+}
+// 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];
}
- },
- getCellAt: function getCellAt(row, col) {
- if (this.isValidPosition(row, col)) {
- return this.grid[row][col];
- }
- return null;
- },
- isValidPosition: function isValidPosition(row, col) {
- return row >= 0 && row < GRID_ROWS && col >= 0 && col < GRID_COLS;
}
+ return null;
};
-// Initialize the game
-gameState.initialize();
-// Game update function
-game.update = function () {
- // Game logic that needs to run every frame can go here
-};
\ No newline at end of file
+// 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;
+// 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