Code edit (3 edits merged)
Please save this source code
User prompt
remove all atack logic
Code edit (2 edits merged)
Please save this source code
User prompt
Create a new attack Function with different aproach and add to the playerController
User prompt
Just create an player1controller, dont add any logic to it
Code edit (1 edits merged)
Please save this source code
User prompt
Remake game.handleCellClick
Code edit (2 edits merged)
Please save this source code
User prompt
when the player clicks to attack, it doesnt perform the attack, refactor hadleCellClick
User prompt
remake attackCell function
Code edit (1 edits merged)
Please save this source code
User prompt
fix to why is it not performing when calling it
User prompt
rewrite the whole attackfunction
User prompt
not performing attack
User prompt
attack function not attacking
User prompt
player 2 cant move
User prompt
the player attack is not working
User prompt
make player vs ai one level, and player vs player a another level
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'setText')' in or related to this line: 'game.statusText.setText('Player Turn');' Line Number: 2065
User prompt
Please fix the bug: 'TypeError: game.clearAllHighlights is not a function' in or related to this line: 'game.clearAllHighlights();' Line Number: 2061
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'setText')' in or related to this line: 'game.statusText.setText('Player Turn');' Line Number: 2065
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
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Critical damage effect class removed var DifficultySelectWindow = Container.expand(function () { var self = Container.call(this); // Semi-transparent background overlay to focus on the popup var overlay = LK.getAsset('grid_cell_dark', { anchorX: 0, anchorY: 0, width: 2048, height: 2732, alpha: 0.7 }); self.addChild(overlay); // Main popup window var popup = LK.getAsset('grid_cell', { anchorX: 0.5, anchorY: 0.5, width: 1200, height: 800, alpha: 0.95 }); popup.x = 1024; popup.y = 1366; self.addChild(popup); // Title for the popup var titleText = new Text2('SELECT DIFFICULTY', { size: 100, fill: '#000000' }); titleText.anchor.set(0.5, 0); titleText.x = 1024; titleText.y = 1066; self.addChild(titleText); // Create buttons for each difficulty var createDifficultyButton = function createDifficultyButton(text, yOffset) { var button = new Container(); // Button background var bg = LK.getAsset('grid_cell', { anchorX: 0.5, anchorY: 0.5, alpha: 0.8, width: 700, height: 120 }); button.addChild(bg); // Button text var buttonText = new Text2(text, { size: 80, fill: '#000000' }); buttonText.anchor.set(0.5, 0.5); button.addChild(buttonText); // Position button button.x = 1024; button.y = yOffset; // Button press animation button.down = function (x, y, obj) { tween(bg, { scaleX: 0.95, scaleY: 0.95 }, { duration: 100, easing: tween.easeOutQuad }); }; button.up = function (x, y, obj) { tween(bg, { scaleX: 1, scaleY: 1 }, { duration: 200, easing: tween.elasticOut }); }; return button; }; // Create difficulty buttons var easyButton = createDifficultyButton('EASY', 1266); var mediumButton = createDifficultyButton('MEDIUM', 1416); var hardButton = createDifficultyButton('HARD', 1566); // Add buttons to container self.addChild(easyButton); self.addChild(mediumButton); self.addChild(hardButton); // Close popup when clicking outside overlay.down = function (x, y, obj) { // Check if click is outside the popup area var localPos = popup.toLocal({ x: x, y: y }); if (Math.abs(localPos.x) > popup.width / 2 || Math.abs(localPos.y) > popup.height / 2) { game.closeDifficultyWindow(); } }; // Button functionality - currently these don't do anything specific // except close the window since difficulty isn't implemented yet easyButton.up = function (x, y, obj) { tween(easyButton.children[0], { scaleX: 1, scaleY: 1 }, { duration: 200, easing: tween.elasticOut, onFinish: function onFinish() { game.closeDifficultyWindow(); // Set AI difficulty to easy (0.3 out of 1.0) game.aiDifficulty = 0.3; game.gameMode = 'pvai'; game.aiControlsRedTeam = true; game.startGame(); } }); }; mediumButton.up = function (x, y, obj) { tween(mediumButton.children[0], { scaleX: 1, scaleY: 1 }, { duration: 200, easing: tween.elasticOut, onFinish: function onFinish() { game.closeDifficultyWindow(); // Set AI difficulty to medium (0.6 out of 1.0) game.aiDifficulty = 0.6; game.gameMode = 'pvai'; game.aiControlsRedTeam = true; game.startGame(); } }); }; hardButton.up = function (x, y, obj) { tween(hardButton.children[0], { scaleX: 1, scaleY: 1 }, { duration: 200, easing: tween.elasticOut, onFinish: function onFinish() { game.closeDifficultyWindow(); // Set AI difficulty to hard (0.9 out of 1.0) game.aiDifficulty = 0.9; game.gameMode = 'pvai'; game.aiControlsRedTeam = true; game.startGame(); } }); }; return self; }); var GameModeScreen = 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: -500 }); self.addChild(logo); // Title text var titleText = new Text2('SELECT GAME MODE', { size: 150, fill: '#FFFFFF' }); titleText.anchor.set(0.5, 0); titleText.y = 0; self.addChild(titleText); // Create a button for game mode selection var createButton = 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: text === 'PLAYER VS PLAYER' ? 1000 : text === 'BACK' ? 500 : 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 press animation button.down = function (x, y, obj) { tween(bg, { scaleX: 0.95, scaleY: 0.95 }, { duration: 100, easing: tween.easeOutQuad }); }; button.up = function (x, y, obj) { tween(bg, { scaleX: 1, scaleY: 1 }, { duration: 200, easing: tween.elasticOut }); }; return button; }; // Create buttons for the two game modes var pvpButton = createButton('PLAYER VS PLAYER', 300); var pvaiButton = createButton('PLAYER VS AI', 500); // Add back button var backButton = createButton('BACK', 1200); // Add buttons to container self.addChild(pvpButton); self.addChild(pvaiButton); self.addChild(backButton); // Animate buttons with grow and shrink effect 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); } // Start button animations with staggered delays animateButton(pvpButton, 0); animateButton(pvaiButton, 300); animateButton(backButton, 600); // Button functionality pvpButton.up = function (x, y, obj) { tween(pvpButton.children[0], { scaleX: 1, scaleY: 1 }, { duration: 200, easing: tween.elasticOut, onFinish: function onFinish() { // Player vs Player mode - start game directly, disable AI game.aiControlsRedTeam = false; game.gameMode = 'pvp'; game.startGame(); } }); }; pvaiButton.up = function (x, y, obj) { tween(pvaiButton.children[0], { scaleX: 1, scaleY: 1 }, { duration: 200, easing: tween.elasticOut, onFinish: function onFinish() { // Show difficulty selection for AI mode game.showDifficultyWindow(); } }); }; backButton.up = function (x, y, obj) { tween(backButton.children[0], { scaleX: 1, scaleY: 1 }, { duration: 200, easing: tween.elasticOut, onFinish: function onFinish() { game.showTitleScreen(); } }); }; 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 === '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' && selectedUnit && selectedUnit.team === 'blue' || game.gameState === 'aiTurn' && selectedUnit && selectedUnit.team === 'red') { game.handleCellClick(self); } }; return self; }); var PlayerController = Container.expand(function () { var self = Container.call(this); // Initialize with player and game reference self.init = function (player, gameRef) { self.player = player; self.game = gameRef; return 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, height: 100, 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, height: 80 }); indicator.x = initialState ? 950 : 850; indicator.y = 0; container.addChild(indicator); // State container.state = initialState; // Toggle functionality toggleBg.down = function (x, y, obj) { container.state = !container.state; tween(indicator, { x: container.state ? 950 : 850 }, { duration: 200, easing: tween.easeOutQuad }); }; 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, 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 = 800; 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(); } }); }; 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) { 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) { tween(bg, { scaleX: 0.95, scaleY: 0.95 }, { duration: 100, easing: tween.easeOutQuad }); }; button.up = function (x, y, obj) { tween(bg, { scaleX: 1, scaleY: 1 }, { duration: 200, 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, 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); } // Start button animations with staggered delays animateButton(playButton, 0); animateButton(tutorialButton, 300); animateButton(settingsButton, 600); // Button functionality playButton.down = function (x, y, obj) { tween(playButton.children[0], { scaleX: 0.95, scaleY: 0.95 }, { duration: 100, easing: tween.easeOutQuad }); }; playButton.up = function (x, y, obj) { tween(playButton.children[0], { scaleX: 1, scaleY: 1 }, { duration: 200, easing: tween.elasticOut, onFinish: function onFinish() { game.showGameModeScreen(); } }); }; tutorialButton.down = function (x, y, obj) { tween(tutorialButton.children[0], { scaleX: 0.95, scaleY: 0.95 }, { duration: 100, easing: tween.easeOutQuad }); }; tutorialButton.up = function (x, y, obj) { tween(tutorialButton.children[0], { scaleX: 1, scaleY: 1 }, { duration: 200, easing: tween.elasticOut, onFinish: function onFinish() { game.showTutorial(); } }); }; settingsButton.down = function (x, y, obj) { tween(settingsButton.children[0], { scaleX: 0.95, scaleY: 0.95 }, { duration: 100, easing: tween.easeOutQuad }); }; settingsButton.up = function (x, y, obj) { tween(settingsButton.children[0], { scaleX: 1, scaleY: 1 }, { duration: 200, easing: tween.elasticOut, onFinish: function onFinish() { game.showSettings(); } }); }; 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) { if (grid[targetRow][targetCol].occupied) { return false; } // 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++) { // Add occupation check here 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); self.canMoveTo = function (targetRow, targetCol) { if (grid[targetRow][targetCol].occupied) { return false; } var rowDiff = Math.abs(targetRow - self.row); var colDiff = Math.abs(targetCol - self.col); 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); self.canMoveTo = function (targetRow, targetCol) { if (grid[targetRow][targetCol].occupied) { return false; } var rowDiff = Math.abs(targetRow - self.row); var colDiff = Math.abs(targetCol - self.col); 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); self.canMoveTo = function (targetRow, targetCol) { if (grid[targetRow][targetCol].occupied) { return false; } var rowDiff = Math.abs(targetRow - self.row); var colDiff = Math.abs(targetCol - self.col); 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); self.canMoveTo = function (targetRow, targetCol) { if (grid[targetRow][targetCol].occupied) { return false; } var rowDiff = Math.abs(targetRow - self.row); var colDiff = Math.abs(targetCol - self.col); 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); self.canMoveTo = function (targetRow, targetCol) { if (grid[targetRow][targetCol].occupied) { return false; } var rowDiff = Math.abs(targetRow - self.row); var colDiff = Math.abs(targetCol - self.col); if (self.team === 'blue') { return colDiff > 0 && rowDiff === 0 || targetRow === self.row - self.moveRange && colDiff === 0; } else { return colDiff > 0 && rowDiff === 0 || targetRow === self.row + self.moveRange && colDiff === 0; } }; // 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 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 ****/ // Attack highlight asset removed // 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 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 // Initialize grid as a 2D array of empty objects to avoid undefined references var grid = []; for (var row = 0; row < GRID_ROWS; row++) { grid[row] = []; for (var col = 0; col < GRID_COLS; col++) { grid[row][col] = {}; } } var units = []; var selectedUnit = null; var gameState = 'mainMenu'; // mainMenu, tutorial, settings, playerTurn, aiTurn, gameOver var gameMode = null; // 'pvp' for player vs player, 'pvai' for player vs AI 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 settingsScreen = new SettingsScreen(); var gameModeScreen = new GameModeScreen(); var difficultyWindow = new DifficultySelectWindow(); // 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); } }; // 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 var background = LK.getAsset('background', { anchorX: 0, anchorY: 0, x: 0, y: 0, 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); 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 units // For blue team: clickable during player 1's turn // For red team: clickable during player 2's turn if PvP mode or AI is disabled if (team === 'blue') { unit.down = function (x, y, obj) { if (game.gameState === 'playerTurn') { selectUnit(unit); } }; } else if (team === 'red') { unit.down = function (x, y, obj) { if (game.gameState === 'aiTurn' && (game.gameMode === 'pvp' || !game.aiControlsRedTeam)) { 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 no unit is selected, we can't do anything if (!selectedUnit) { return; } // If cell is empty and it's a valid move, move the unit if (!cell.occupied && selectedUnit.canMoveTo(cell.row, cell.col)) { moveSelectedUnit(cell.row, cell.col); return; } // Attack logic removed // If we click on a highlighted cell that isn't the current unit's cell if (cell.highlighted && !(cell.row === selectedUnit.row && cell.col === selectedUnit.col)) { if (cell.highlightType === 'move') { moveSelectedUnit(cell.row, cell.col); } // Attack highlight logic removed } }; // 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); } // Attack highlighting removed } // 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; // Attack check removed // Switch turns endTurn(); } }); } // Attack a cell function attackCell(cell) { // Empty placeholder function since attack logic is removed console.log("Attack functionality has been removed"); return false; } // Auto-attack function removed // 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() { // Store the current state before any changes var currentState = gameState; if (currentState === 'playerTurn') { // Update state first before AI processing gameState = 'aiTurn'; // Update text based on game mode and whether AI or Player 2 is controlling red team if (game.gameMode === 'pvp') { statusText.setText('Player 2 Turn'); } else { statusText.setText(game.aiControlsRedTeam ? 'AI Turn' : 'Player 2 Turn'); } // If AI controls red team and we're in PvAI mode, let AI make a move after delay if (game.aiControlsRedTeam && game.gameMode === 'pvai') { // 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 gameState = 'playerTurn'; statusText.setText('Player Turn'); } } }, 500); // Small delay for better user experience } } 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!'); LK.showYouWin(); } else { statusText.setText('Game Over'); LK.showGameOver(); } } // Critical damage functions removed // 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 = function (cell) { // Empty placeholder function to replace attackCell console.log("Attack functionality has been removed"); return false; }; 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 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 scrollIndicator.x = 1950 + tutorialOffset.x; scrollIndicator.y = 1366 + tutorialOffset.y; } }; // Show difficulty selection window game.showDifficultyWindow = function () { game.addChild(difficultyWindow); }; // Close difficulty selection window game.closeDifficultyWindow = function () { game.removeChild(difficultyWindow); }; // 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); game.removeChild(gameModeScreen); // 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); game.removeChild(gameModeScreen); // Set game state gameState = 'tutorial'; }; game.showSettings = function () { // Show settings screen game.removeChild(titleScreen); game.removeChild(tutorialScreen); game.removeChild(gameModeScreen); game.addChild(settingsScreen); // Set game state gameState = 'settings'; }; game.showGameModeScreen = function () { // Show game mode selection screen game.removeChild(titleScreen); game.removeChild(tutorialScreen); game.removeChild(settingsScreen); game.addChild(gameModeScreen); // Center the screen gameModeScreen.x = 1024; gameModeScreen.y = 1366; // Set game state gameState = 'gameMode'; }; game.startGame = function () { // Clear screens game.removeChild(titleScreen); game.removeChild(tutorialScreen); game.removeChild(settingsScreen); game.removeChild(gameModeScreen); // Set default game mode if not already set if (game.gameMode === undefined || game.gameMode === null) { game.gameMode = 'pvai'; // Default to Player vs AI } // Set default AI difficulty if not already set if (game.aiDifficulty === undefined) { game.aiDifficulty = 0.3; // Default to easy } // Ensure aiControlsRedTeam is set properly if (game.aiControlsRedTeam === undefined) { game.aiControlsRedTeam = game.gameMode === 'pvai'; // Only let AI control red team in PvAI mode } // 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.attachAsset('grid_cell_dark', { anchorX: 0.5, anchorY: 0.5, alpha: 0.5 }); } grid[row][col] = cell; game.addChild(cell); } } // Create units createUnits(); // Show status text during gameplay statusText.visible = true; // Set game state to player's turn gameState = 'playerTurn'; statusText.setText('Player Turn'); // Deselect any selected unit selectedUnit = null; // Clear all highlights clearAllHighlights(); }; // Remove all game elements (grid cells and units) 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]); } } } // Remove units for (var i = 0; i < units.length; i++) { game.removeChild(units[i]); } // Reset game variables and re-initialize grid as empty objects to avoid undefined references grid = []; for (var row = 0; row < GRID_ROWS; row++) { grid[row] = []; for (var col = 0; col < GRID_COLS; col++) { grid[row][col] = {}; } } units = []; selectedUnit = null; }; // Initialize game initializeGame();
===================================================================
--- original.js
+++ change.js
@@ -5,60 +5,9 @@
/****
* Classes
****/
-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;
-});
+// Critical damage effect class removed
var DifficultySelectWindow = Container.expand(function () {
var self = Container.call(this);
// Semi-transparent background overlay to focus on the popup
var overlay = LK.getAsset('grid_cell_dark', {
@@ -373,14 +322,8 @@
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,
@@ -1529,8 +1472,9 @@
/****
* Game Code
****/
+// Attack highlight asset removed
// Add global vector for tutorial content positioning
// Import tween plugin
// Game constants
// Background image asset
@@ -1553,10 +1497,8 @@
var units = [];
var selectedUnit = null;
var gameState = 'mainMenu'; // mainMenu, tutorial, settings, playerTurn, aiTurn, gameOver
var gameMode = null; // 'pvp' for player vs player, 'pvai' for player vs AI
-var ai = new AIPlayer();
-ai.game = game; // Properly pass game reference to AI player
var statusText = new Text2('Player Turn', {
size: 120,
// Significantly increased text size
fill: 0xFFFFFF
@@ -1751,20 +1693,15 @@
if (!cell.occupied && selectedUnit.canMoveTo(cell.row, cell.col)) {
moveSelectedUnit(cell.row, cell.col);
return;
}
- // If cell contains an enemy unit and it's a valid attack, attack it
- if (cell.occupied && cell.occupiedBy.team !== selectedUnit.team && selectedUnit.canAttack(cell.row, cell.col)) {
- game.attackCell(cell);
- return;
- }
+ // Attack logic removed
// If we click on a highlighted cell that isn't the current unit's cell
if (cell.highlighted && !(cell.row === selectedUnit.row && cell.col === selectedUnit.col)) {
if (cell.highlightType === 'move') {
moveSelectedUnit(cell.row, cell.col);
- } else if (cell.highlightType === 'attack') {
- attackCell(cell);
}
+ // Attack highlight logic removed
}
};
// Select a unit
function selectUnit(unit) {
@@ -1816,21 +1753,9 @@
}
}, 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);
- }
+ // Attack highlighting removed
}
// Move selected unit to new position
function moveSelectedUnit(targetRow, targetCol) {
if (!selectedUnit) {
@@ -1857,158 +1782,21 @@
// Deselect unit and clear highlights
selectedUnit.deselect();
clearAllHighlights();
selectedUnit = null;
- // Check if any attacks are possible after movement
- checkForAutoAttack();
+ // Attack check removed
// Switch turns
endTurn();
}
});
}
// Attack a cell
function attackCell(cell) {
- // Basic validation - ensure we have a selected unit and a valid target
- if (!selectedUnit) {
- console.log("No unit selected for attack");
- return false;
- }
- // Make sure the cell is occupied by an enemy
- if (!cell.occupied || cell.occupiedBy.team === selectedUnit.team) {
- console.log("Invalid target: empty cell or friendly unit");
- return false;
- }
- var targetUnit = cell.occupiedBy;
- // Check if this is a valid attack based on unit type and position
- if (!selectedUnit.canAttack(cell.row, cell.col)) {
- console.log("Target not in attack range");
- return false;
- }
- // Calculate damage
- var damage = selectedUnit.attackStrength;
- var isCritical = isCriticalDamage(selectedUnit.type, targetUnit.type);
- if (isCritical) {
- damage *= getCriticalDamageMultiplier();
- // Show critical hit effect
- var critEffect = new CriticalDamageEffect().init(damage, targetUnit.x, targetUnit.y - 100);
- game.addChild(critEffect);
- }
- // For warrior's instant kill ability
- if (selectedUnit.hasInstantKill && !targetUnit.isKing) {
- damage = targetUnit.health;
- }
- // Animate the attack
- var originalX = selectedUnit.x;
- var originalY = selectedUnit.y;
- var midX = (selectedUnit.x + targetUnit.x) / 2;
- var midY = (selectedUnit.y + targetUnit.y) / 2;
- // Move toward target
- tween(selectedUnit, {
- x: midX,
- y: midY
- }, {
- duration: 150,
- easing: tween.easeOutQuad,
- onFinish: function onFinish() {
- // Flash target red to indicate damage
- LK.effects.flashObject(targetUnit, 0xff0000, 300);
- // Show damage number
- var damageText = new Text2('-' + damage, {
- size: 80,
- fill: isCritical ? '#FFFF00' : '#FFFFFF'
- });
- damageText.anchor.set(0.5, 0.5);
- damageText.x = targetUnit.x;
- damageText.y = targetUnit.y - 50;
- game.addChild(damageText);
- // Animate damage text up and fade out
- tween(damageText, {
- y: damageText.y - 100,
- alpha: 0
- }, {
- duration: 800,
- easing: tween.easeOutQuad,
- onFinish: function onFinish() {
- game.removeChild(damageText);
- }
- });
- // Apply damage
- targetUnit.health -= damage;
- // Update health display
- if (targetUnit.health <= 0) {
- targetUnit.health = 0;
- }
- targetUnit.healthText.setText(targetUnit.health.toString());
- // Move back to original position
- tween(selectedUnit, {
- x: originalX,
- y: originalY
- }, {
- duration: 150,
- easing: tween.easeOutQuad,
- onFinish: function onFinish() {
- // Check if target is defeated
- if (targetUnit.health <= 0) {
- // Kill animation
- tween(targetUnit, {
- alpha: 0,
- scaleX: 0.3,
- scaleY: 0.3
- }, {
- duration: 400,
- easing: tween.easeOutQuad,
- onFinish: function onFinish() {
- removeUnit(targetUnit);
- }
- });
- }
- // If this is a wizard (area attacker), also damage adjacent units
- if (selectedUnit.isAreaAttacker) {
- var adjacentCells = getAdjacentCells(cell.row, cell.col);
- var splashDamage = Math.floor(damage * 0.5);
- for (var i = 0; i < adjacentCells.length; i++) {
- var adjCell = adjacentCells[i];
- if (adjCell.occupied && adjCell.occupiedBy.team !== selectedUnit.team) {
- // Apply splash damage
- adjCell.occupiedBy.health -= splashDamage;
- if (adjCell.occupiedBy.health <= 0) {
- adjCell.occupiedBy.health = 0;
- // Kill animation for adjacent units
- tween(adjCell.occupiedBy, {
- alpha: 0,
- scaleX: 0.3,
- scaleY: 0.3
- }, {
- duration: 400,
- easing: tween.easeOutQuad,
- onFinish: function onFinish() {
- removeUnit(adjCell.occupiedBy);
- }
- });
- }
- // Update health display
- adjCell.occupiedBy.healthText.setText(adjCell.occupiedBy.health.toString());
- // Flash effect
- LK.effects.flashObject(adjCell.occupiedBy, 0xff0000, 300);
- }
- }
- }
- // Deselect current unit
- selectedUnit.deselect();
- clearAllHighlights();
- selectedUnit = null;
- // End turn
- endTurn();
- }
- });
- }
- });
- return true;
+ // Empty placeholder function since attack logic is removed
+ console.log("Attack functionality has been removed");
+ return false;
}
-// 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
-}
+// Auto-attack function removed
// Get adjacent cells
function getAdjacentCells(row, col) {
var adjacent = [];
var directions = [{
@@ -2121,30 +1909,9 @@
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;
-}
+// Critical damage functions removed
// Helper functions
game.getTeamUnits = function (team) {
return units.filter(function (unit) {
return unit.team === team;
@@ -2160,9 +1927,13 @@
};
// Expose functions to game object for access from other classes
game.selectUnit = selectUnit;
game.moveSelectedUnit = moveSelectedUnit;
-game.attackCell = attackCell;
+game.attackCell = function (cell) {
+ // Empty placeholder function to replace attackCell
+ console.log("Attack functionality has been removed");
+ return false;
+};
game.grid = grid;
game.gameState = gameState;
game.getAdjacentCells = getAdjacentCells;
// Create a getter/setter for game state to ensure consistency
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