Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: '_Vector is not a constructor' in or related to this line: 'var tutorialOffset = new _Vector(0, 0);' Line Number: 1462
User prompt
Make an global Vector2 variable to move all elements in the tutorial screen
User prompt
thing are overlaping the tutorial screen adjust that and make it be centered in the screen and no elements overlaping
User prompt
for the tutorial screen: Design the layout for a single-page mobile game tutorial menu. The page should be scrollable and include the following sections: "Tactical Kings: Tutorials" (Top-center) "Core Concepts" (Section title) [Explanations and visuals for Core Concepts] "Character Guides" (Section title) [Explanations and visuals for Character Guides] "Advanced Tactics" (Section title) [Explanations and visuals for Advanced Tactics] A fixed "Back" button (Bottom-left) Optimize text for readability on mobile devices and recommend visual aids (e.g., diagrams, animations, illustrations).
User prompt
For the tutorial screen Design the structure for a single-page mobile game tutorial screen with a "Back" button at the bottom-left. The page should be scrollable and include the following sections: Title: "Tactical Kings: Tutorials" (Top-center) Core Concepts: Explanation of game objective, turn-based gameplay, and attack zones. Character Guides: Overview of each character (Spear Knight, Archer, Mage, Tank, King), including their role, stats, and movement. Advanced Tactics: Explanation of unit counters and strategic positioning.
User prompt
The tutorial menu screen should be full-screen and use a vertical list layout. The title should be "Tactical Kings: Tutorials" at the top-center. Include buttons for "Core Concepts," "Character Guides," "Advanced Tactics," and an optional "Multiplayer" button.
User prompt
Delete the Main Menu Title, but keep everything else in the same position
User prompt
Remove the main menu title
User prompt
Create and Add an image to be the logo of the game in the main menu
Code edit (2 edits merged)
Please save this source code
User prompt
var TutorialScreen = Container.expand(function () { var self = Container.call(this); // Title var titleText = new Text2('TUTORIAL', { size: 150, fill: '#FFFFFF' }); titleText.anchor.set(0.5, 0); titleText.y = 2732 / 3 -150; // Position in top third of screen this variable is not changing the position of the title: titleText.y = 2732 / 3 -150; // Position in top third of screen
Code edit (1 edits merged)
Please save this source code
User prompt
The Tutorial texts are overlapping, fix their position, the Tutorial page title should be in the top third of the screen centered in x
User prompt
Animate grow and shrink each button, on move the title to the top third of the screen centered in x ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Create a new level for the main menu
User prompt
Add an background image
User prompt
the archer must attack any enemy character in the line with attackRange tiles forward of him ex: x x x x x <- attack any character in this line _ _ _ archer
User prompt
change the attack zone of the archers, to be any tile in the line of its attackRange
User prompt
the wizard has attack range of 3, correct the code to correspond to these variables: 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
User prompt
you should update the values of each character for both teams and make the ai react accordingly
Code edit (1 edits merged)
Please save this source code
User prompt
create something like this but for the movement and attack zones: switch (type) { case 'king': self.health = 200; self.attackStrength = 30; break; case 'warrior': self.health = 250; self.attackStrength = 40; break; case 'knight': self.health = 130; self.attackStrength = 35; break; case 'wizard': self.health = 80; self.attackStrength = 50; break; case 'archer': self.health = 90; self.attackStrength = 45; break;
User prompt
change the color of the health text to be golden yellow
Code edit (1 edits merged)
Please save this source code
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var AIPlayer = Container.expand(function () {
var self = Container.call(this);
self.makeMove = function () {
// Only make a move if it's AI's turn
if (game.gameState !== 'aiTurn') {
return false;
}
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;
}
// Look for advantageous critical attacks first
var criticalAttack = attacks.find(function (attack) {
var target = game.grid[attack.row][attack.col].occupiedBy;
return target && 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;
for (var j = 0; j < attacks.length; j++) {
var attack = attacks[j];
var adjacentCells = 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 (enemyCount > bestCount) {
bestCount = enemyCount;
bestAttack = attack;
}
}
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;
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 (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));
// Special movement strategy based on unit type
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) {
moveScore += 3;
}
} 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) {
moveScore += 4;
}
} else if (closestUnit.type === 'wizard') {
// Wizards prefer positions that might hit multiple units next turn
var adjacentCells = 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;
}
}
}
// 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;
}
}
return false;
});
if (unitsInDanger.length > 0) {
// Prioritize king safety
var unitToSave = unitsInDanger.find(function (unit) {
return unit.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;
for (var i = 0; i < moves.length; i++) {
var move = moves[i];
var safetyScore = 0;
// Calculate safety based on distance from all player units
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;
}
}
}
// 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 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,
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);
// 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;
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 = 1; // Can move 1 tile in any direction
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
});
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 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 moveRange spaces
return rowDiff <= self.moveRange && colDiff <= self.moveRange && !(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;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Background image asset
// Game constants
// Import tween plugin
var GRID_ROWS = 10;
var GRID_COLS = 5;
var CELL_SIZE = 250; // Significantly increased cell size
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: 120,
// Significantly increased text size
fill: 0xFFFFFF
});
// Initialize the game board
function initializeGame() {
// Add background image first so it's behind other elements
var background = LK.getAsset('background', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
width: 2048,
height: 2732
});
game.addChild(background);
// 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
// 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);
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);
// 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);
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);
}
// 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 health display
unit.healthText = new Text2(unit.health.toString(), {
size: 50,
fill: 0xFFD700 // Golden yellow color for better visibility
});
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);
}
};
}
// 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
});
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);
}
};
// 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();
// Enhanced selection animation with glow effect
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,
alpha: 0.9
}, {
duration: 200,
easing: tween.easeOutQuad
});
}
});
// 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
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,
y: targetY
}, {
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;
}
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 distance = Math.sqrt(directionX * directionX + directionY * directionY);
var normalizedX = directionX / distance * 30; // small lunge
var normalizedY = directionY / distance * 30;
// Enhanced attack animation sequence
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);
}
}
} 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
}, {
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); // Half damage for adjacent units
adjTargetUnit.health -= adjDamage;
adjTargetUnit.healthText.setText(adjTargetUnit.health.toString());
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
}, {
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);
}
}
// 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');
// Execute AI turn with delay for better visibility
LK.setTimeout(function () {
if (ai.makeMove()) {
// AI successfully made a move, turn will be ended in the attack/move handlers
} else {
// AI couldn't make a move, switch back to player
gameState = 'playerTurn';
statusText.setText('Player Turn');
}
}, 500); // Small delay for better user experience
} 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 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;
}
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];
}
}
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;
}
});
// Initialize game
initializeGame(); ===================================================================
--- original.js
+++ change.js
@@ -576,8 +576,9 @@
/****
* Game Code
****/
+// Background image asset
// Game constants
// Import tween plugin
var GRID_ROWS = 10;
var GRID_COLS = 5;
@@ -596,8 +597,18 @@
fill: 0xFFFFFF
});
// Initialize the game board
function initializeGame() {
+ // Add background image first so it's behind other elements
+ var background = LK.getAsset('background', {
+ anchorX: 0,
+ anchorY: 0,
+ x: 0,
+ y: 0,
+ width: 2048,
+ height: 2732
+ });
+ game.addChild(background);
// Create grid
for (var row = 0; row < GRID_ROWS; row++) {
grid[row] = [];
for (var col = 0; col < GRID_COLS; col++) {
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