Code edit (1 edits merged)
Please save this source code
User prompt
That did not work, for some reasons they seem centered at X. Maybe you can do x - screen_width/2 ?
User prompt
Im not sure but the Health bar both player and AI start in the middle of the screen. They should start at the left and go all the way to the right at 100 of like. The text shouldbe right in the middle.
Code edit (1 edits merged)
Please save this source code
User prompt
Instead of Player life: XXX and AI Life: XXX on the top right, I want 2 health bar on the bottom, full width, one for player another for AI. Bottom of the screen.
User prompt
Instead of YOUR COMBO when one element only is selected, write the name of the element
Code edit (1 edits merged)
Please save this source code
User prompt
Dont write + ? in the combos
User prompt
Use container.cursor in Pixi to set the cursor when hovering over elements as a hand / selectable cursor
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'body')' in or related to this line: 'document.body.style.cursor = 'default';' Line Number: 2173
User prompt
Do it
Code edit (1 edits merged)
Please save this source code
User prompt
Instead of XXXX + YYYYY defeats ZZZZZ + WWWWW or similar, write please the name of the combos. If it's one element, then it's ok to write only the element
User prompt
In the battle screen, instead of showing BATTLE, show (COMBO1 (or element1) \n VS COMBO2 (or element2))
User prompt
Ok. Now, make up names for each of the possible combos. And then istead of YOUR COMBO: or AI COMBO: just show the name of the combo.
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'Cannot read properties of undefined (reading 'baseTexture')' in or related to this line: 'var isCurrentlyBoosted = background.texture.baseTexture && background.texture.baseTexture.imageUrl && background.texture.baseTexture.imageUrl.includes('boostedElementButton');' Line Number: 630
Code edit (1 edits merged)
Please save this source code
User prompt
THis is not enough: if (hasWeatherBonus(element)) { Also add to that if that IF THE element is not disabled because it was used. If it was disabled then go to the else
Code edit (1 edits merged)
Please save this source code
User prompt
If an element button is disabled, don't use the boosted version of the element button but the normal elementButton
Code edit (7 edits merged)
Please save this source code
User prompt
Please fix the bug: 'ReferenceError: battleResultText is not defined' in or related to this line: 'battleResultText.setText(resultText);' Line Number: 1617
User prompt
Show battle result can't reuse the BATTLE! label to show the result (tie, win, defeat, etc)! Create a new one, similar place but it's a new label
User prompt
user or AI can't never select twice the same element for a combo.
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var BattleElement = Container.expand(function (elementType, isPlayer, comboElements) { var self = Container.call(this); self.elementType = elementType; self.isPlayer = isPlayer; var background = self.attachAsset('elementButton', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.5, scaleY: 1.5 }); var icon = self.attachAsset(elementType, { anchorX: 0.5, anchorY: 0.5, scaleX: 1.2, scaleY: 1.2 }); var label = new Text2(elementType.toUpperCase(), { size: 32, fill: 0xffffff, font: "Trebuchet MS, Arial, sans-serif", stroke: 0x000000, strokeThickness: 3 }); label.anchor.set(0.5, 0.5); label.y = 220; self.addChild(label); // Add second element label if this is a combo self.addSecondElementLabel = function (secondElementType) { var secondLabel = new Text2(secondElementType.toUpperCase(), { size: 20, fill: 0xffffff, font: "Trebuchet MS, Arial, sans-serif", stroke: 0x000000, strokeThickness: 2 }); secondLabel.anchor.set(0.5, 0.5); secondLabel.y = -180; secondLabel.x = isPlayer ? 130 : -80; self.addChild(secondLabel); }; self.playWinAnimation = function () { var effect = self.attachAsset('winEffect', { anchorX: 0.5, anchorY: 0.5, alpha: 0.7 }); tween(self, { scaleX: 1.3, scaleY: 1.3 }, { duration: 500 }); tween(effect, { scaleX: 2, scaleY: 2, alpha: 0 }, { duration: 800, onFinish: function onFinish() { self.removeChild(effect); } }); }; self.playLoseAnimation = function () { var effect = self.attachAsset('loseEffect', { anchorX: 0.5, anchorY: 0.5, alpha: 0.7 }); tween(self, { scaleX: 0.7, scaleY: 0.7, alpha: 0.5 }, { duration: 500 }); tween(effect, { scaleX: 2, scaleY: 2, alpha: 0 }, { duration: 800, onFinish: function onFinish() { self.removeChild(effect); } }); }; return self; }); var ElementButton = Container.expand(function (elementType, index) { var self = Container.call(this); self.elementType = elementType; self.index = index; self.isSelected = false; self.isDisabled = false; var button = self.attachAsset('elementButton', { anchorX: 0.5, anchorY: 0.5 }); var icon = self.attachAsset(elementType, { anchorX: 0.5, anchorY: 0.5 }); var label = new Text2(elementType.toUpperCase(), { size: 24, fill: 0xffffff, font: "Trebuchet MS, Arial, sans-serif", stroke: 0x000000, strokeThickness: 2 }); label.anchor.set(0.5, 0.5); self.addChild(label); // Position text toward wheel center self.positionTextTowardCenter = function (centerX, centerY) { var angle = Math.atan2(self.y - centerY, self.x - centerX); var offsetX = Math.cos(angle) * textOffsetTowardCenter * 1.3; var offsetY = Math.sin(angle) * textOffsetTowardCenter * 1.3; label.x = -offsetX; label.y = -offsetY; }; self.setSelected = function (selected) { self.isSelected = selected; if (selected) { button.tint = 0xffd700; tween(self, { scaleX: 1.2, scaleY: 1.2 }, { duration: 200 }); } else { button.tint = 0xffffff; tween(self, { scaleX: 1.0, scaleY: 1.0 }, { duration: 200 }); } }; self.setDisabled = function (disabled) { self.isDisabled = disabled; if (disabled) { button.alpha = 0.5; icon.alpha = 0.5; label.alpha = 0.5; } else { button.alpha = 1.0; icon.alpha = 1.0; label.alpha = 1.0; } }; self.down = function (x, y, obj) { if (gameState === 'selection' && !self.isDisabled) { LK.getSound('select').play(); selectElement(self.elementType); } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0xffffff }); /**** * Game Code ****/ // Add background image - will be updated based on weather var backgroundImage = null; // Function to update background based on current weather function updateBackgroundForWeather() { // Remove existing background if it exists if (backgroundImage) { backgroundImage.destroy(); backgroundImage = null; } // Determine which background asset to use var backgroundAsset = 'background'; // default if (currentWeather === 'drought') { backgroundAsset = 'drought'; } else if (currentWeather === 'rainy') { backgroundAsset = 'rainy'; } else if (currentWeather === 'storm') { backgroundAsset = 'stormy'; } else if (currentWeather === 'windy') { backgroundAsset = 'windy'; } // Create new background with weather-appropriate asset backgroundImage = game.attachAsset(backgroundAsset, { anchorX: 0.5, anchorY: 0.5, scaleX: 1.137, scaleY: 1.013 }); backgroundImage.x = 1024; backgroundImage.y = 1366; // Move background to back game.setChildIndex(backgroundImage, 0); } // Initialize with default background updateBackgroundForWeather(); // Game elements and their relationships var elements = ['rock', 'paper', 'scissors', 'water', 'fire', 'air', 'lightning', 'tree', 'gun', 'sponge', 'smoke', 'gas', 'metal', 'ice', 'sand', 'oil']; // Element defeat relationships (each element defeats 8 others) var defeats = { // Rock: Heavy and solid, crushes fragile things, breaks weapons, absorbs energy 'rock': ['scissors', 'sponge', 'gas', 'metal', 'ice', 'gun', 'tree', 'sand'], // Paper: Wraps and covers, conducts electricity, absorbs liquids, blocks air flow 'paper': ['rock', 'metal', 'water', 'gas', 'sand', 'ice', 'air', 'smoke'], // Scissors: Sharp cutting tool, cuts through soft materials and gases 'scissors': ['paper', 'sponge', 'air', 'tree', 'gas', 'oil', 'ice', 'smoke'], // Water: Extinguishes fire, erodes materials, conducts electricity, flows through spaces 'water': ['fire', 'rock', 'scissors', 'gas', 'oil', 'sand', 'tree', 'metal'], // Fire: Burns combustible materials, melts solids, heats and expands gases 'fire': ['paper', 'scissors', 'sponge', 'ice', 'tree', 'sand', 'oil', 'smoke'], // Air: Feeds fire, disperses gases, creates pressure, moves objects 'air': ['fire', 'gas', 'smoke', 'metal', 'rock', 'oil', 'tree', 'gun'], // Lightning: Electrical discharge, conducts through metals and water, ionizes gases 'lightning': ['water', 'metal', 'gun', 'air', 'paper', 'sponge', 'smoke', 'sand'], // Tree: Absorbs water and nutrients, grows through materials, provides shelter 'tree': ['water', 'paper', 'sponge', 'smoke', 'gun', 'sand', 'ice', 'gas'], // Gun: Projectile weapon, breaks through barriers, fires through gases 'gun': ['scissors', 'rock', 'tree', 'metal', 'gas', 'ice', 'oil', 'paper'], // Sponge: Absorbs liquids and gases, flexible material, filters particles 'sponge': ['water', 'metal', 'air', 'paper', 'gas', 'rock', 'sand', 'smoke'], // Smoke: Obscures vision, suffocates, corrodes metals, covers surfaces 'smoke': ['ice', 'gun', 'rock', 'paper', 'air', 'metal', 'water', 'oil'], // Gas: Expands and fills spaces, displaces air, creates pressure, volatile 'gas': ['paper', 'ice', 'gun', 'smoke', 'air', 'scissors', 'sponge', 'sand'], // Metal: Strong and durable, conducts electricity, resists cutting, heavy 'metal': ['scissors', 'tree', 'ice', 'fire', 'gun', 'oil', 'rock', 'sand'], // Ice: Freezes liquids, slippery surface, preserves, expands when frozen 'ice': ['air', 'water', 'paper', 'sponge', 'fire', 'smoke', 'gun', 'lightning'], // Sand: Abrasive particles, absorbs liquids, extinguishes fire, buries objects 'sand': ['scissors', 'ice', 'gun', 'fire', 'air', 'paper', 'rock', 'lightning'], // Oil: Slippery liquid, flammable, coats surfaces, lubricates mechanisms 'oil': ['rock', 'scissors', 'gun', 'metal', 'water', 'gas', 'lightning', 'fire'] }; // Action keywords for how elements defeat others var actionKeywords = { 'rock': { 'scissors': 'crushes', 'sponge': 'crushes', 'gas': 'disperses', 'metal': 'breaks', 'ice': 'shatters', 'gun': 'blocks', 'tree': 'crushes', 'sand': 'compacts' }, 'paper': { 'rock': 'wraps', 'metal': 'covers', 'water': 'absorbs', 'gas': 'captures', 'sand': 'covers', 'ice': 'insulates', 'air': 'blocks', 'smoke': 'filters' }, 'scissors': { 'paper': 'cuts', 'sponge': 'cuts', 'air': 'cuts', 'tree': 'cuts', 'gas': 'cuts', 'oil': 'cuts', 'ice': 'cuts', 'smoke': 'cuts' }, 'water': { 'fire': 'extinguishes', 'rock': 'erodes', 'scissors': 'rusts', 'gas': 'dissolves', 'oil': 'displaces', 'sand': 'washes', 'tree': 'nourishes', 'metal': 'rusts' }, 'fire': { 'paper': 'burns', 'scissors': 'melts', 'sponge': 'burns', 'ice': 'melts', 'tree': 'burns', 'sand': 'heats', 'oil': 'ignites', 'smoke': 'burns' }, 'air': { 'fire': 'feeds', 'gas': 'disperses', 'smoke': 'clears', 'metal': 'oxidizes', 'rock': 'erodes', 'oil': 'evaporates', 'tree': 'sways', 'gun': 'deflects' }, 'lightning': { 'water': 'electrifies', 'metal': 'conducts', 'gun': 'shorts', 'air': 'ionizes', 'paper': 'ignites', 'sponge': 'shocks', 'smoke': 'disperses', 'sand': 'vitrifies' }, 'tree': { 'water': 'absorbs', 'paper': 'grows over', 'sponge': 'outgrows', 'smoke': 'filters', 'gun': 'blocks', 'sand': 'roots in', 'ice': 'breaks', 'gas': 'absorbs' }, 'gun': { 'scissors': 'shoots', 'rock': 'shatters', 'tree': 'shoots through', 'metal': 'pierces', 'gas': 'ignites', 'ice': 'shatters', 'oil': 'ignites', 'paper': 'pierces' }, 'sponge': { 'water': 'absorbs', 'metal': 'corrodes', 'air': 'filters', 'paper': 'soaks', 'gas': 'absorbs', 'rock': 'erodes', 'sand': 'absorbs', 'smoke': 'filters' }, 'smoke': { 'ice': 'melts', 'gun': 'jams', 'rock': 'corrodes', 'paper': 'stains', 'air': 'pollutes', 'metal': 'corrodes', 'water': 'pollutes', 'oil': 'mixes with' }, 'gas': { 'paper': 'dissolves', 'ice': 'sublimates', 'gun': 'corrodes', 'smoke': 'displaces', 'air': 'displaces', 'scissors': 'corrodes', 'sponge': 'fills', 'sand': 'displaces' }, 'metal': { 'scissors': 'dulls', 'tree': 'cuts', 'ice': 'breaks', 'fire': 'conducts', 'gun': 'reinforces', 'oil': 'repels', 'rock': 'crushes', 'sand': 'compacts' }, 'ice': { 'air': 'freezes', 'water': 'freezes', 'paper': 'freezes', 'sponge': 'freezes', 'fire': 'extinguishes', 'smoke': 'condenses', 'gun': 'jams', 'lightning': 'grounds' }, 'sand': { 'scissors': 'dulls', 'ice': 'melts', 'gun': 'jams', 'fire': 'smothers', 'air': 'fills', 'paper': 'abrades', 'rock': 'erodes', 'lightning': 'grounds' }, 'oil': { 'rock': 'lubricates', 'scissors': 'lubricates', 'gun': 'lubricates', 'metal': 'lubricates', 'water': 'floats on', 'gas': 'dissolves', 'lightning': 'insulates', 'fire': 'feeds' } }; // Game state variables var gameState = 'selection'; // 'selection', 'spinning', 'battle', 'result' var elementButtons = []; var playerElement = null; var aiElement = null; var playerBattleElement = null; var aiBattleElement = null; var vsText = null; var playerLife = 100; var aiLife = 100; var difficultyLevel = 1; var battleTimer = 0; var hoveredButton = null; // Track which button is currently hovered var victoryArrows = []; // Array to store victory arrows var usedPlayerElements = []; // Track elements used by player var usedAIElements = []; // Track elements used by AI var wheelContainer = null; // Container for wheel elements var isWheelSpinning = false; // Track if wheel is currently spinning var wheelRotation = 0; // Current wheel rotation // Combo system variables var playerCombo = []; // Array to store player's selected combo elements var aiCombo = []; // Array to store AI's combo elements var isComboMode = false; // Track if player is building a combo var comboDisplay = null; // UI element to show current combo var aiComboSpins = 0; // Track AI combo wheel spins // Weather system variables var currentWeather = null; var weatherRoundsLeft = 0; var weatherTypes = ['rainy', 'drought', 'windy', 'storm']; var weatherEffects = { 'rainy': ['water', 'ice'], // Water-based elements get bonus 'drought': ['fire', 'sand'], // Fire-based elements get bonus 'windy': ['air', 'gas'], // Air-based elements get bonus 'storm': ['lightning', 'metal'] // Electric/conductive elements get bonus }; // Combo system definitions var comboEffects = { // Special combo combinations with enhanced effects 'lightning+water': { name: 'Electrified Storm', defeatsExtra: ['metal', 'gun', 'scissors'], // Additional defeats beyond normal rules multiplier: 1.5 }, 'fire+air': { name: 'Inferno', defeatsExtra: ['tree', 'paper', 'oil'], multiplier: 2.0 }, 'water+ice': { name: 'Frozen Flood', defeatsExtra: ['fire', 'rock', 'sand'], multiplier: 1.5 }, 'rock+metal': { name: 'Crushing Force', defeatsExtra: ['gun', 'scissors', 'lightning'], multiplier: 1.8 }, 'gas+fire': { name: 'Explosive Blast', defeatsExtra: ['rock', 'metal', 'ice'], multiplier: 2.0 }, 'lightning+metal': { name: 'Electric Conductor', defeatsExtra: ['water', 'ice', 'gun'], multiplier: 1.7 } }; // Function to get the element at the top position function getTopElement() { // At the start, rock (index 0) is at the top (-PI/2) // Calculate angle per element var anglePerElement = Math.PI * 2 / elements.length; // Normalize rotation to 0-2PI range var normalizedRotation = (wheelContainer.rotation % (Math.PI * 2) + Math.PI * 2) % (Math.PI * 2); // Calculate how many element positions we've rotated from the starting position var elementSteps = Math.round(normalizedRotation / anglePerElement); // Find which element is now at the ROCK position (top position) // Since wheel rotates clockwise, we subtract the steps from the starting rock index var topElementIndex = (0 - elementSteps + elements.length * 10) % elements.length; var topElement = elements[topElementIndex]; return topElement; } // Function to start new weather function startNewWeather() { var newWeather = weatherTypes[Math.floor(Math.random() * weatherTypes.length)]; currentWeather = newWeather; weatherRoundsLeft = 1 + Math.floor(Math.random() * 3); // 3-5 rounds updateWeatherDisplay(); } // Function to update weather display // Function to update weather display function updateWeatherDisplay() { var text = ""; if (currentWeather && weatherRoundsLeft > 0) { var weatherName = currentWeather.charAt(0).toUpperCase() + currentWeather.slice(1); var effectElements = weatherEffects[currentWeather].join(', ').toUpperCase(); text = weatherName + ' Season (' + weatherRoundsLeft + ' rounds)\n' + effectElements + ' elements boosted'; } if (weatherText) { weatherText.destroy(); } weatherText = new Text2(text, { size: 28, fill: getWeatherColor(currentWeather), font: "Trebuchet MS, Arial, sans-serif", stroke: 0xffffff, strokeThickness: 3, align: 'center' }); LK.gui.center.addChild(weatherText); weatherText.anchor.set(0.5, 0); LK.gui.top.addChild(weatherText); weatherText.x = 20; weatherText.y = 150; // Position under Wins text // Update background to match current weather updateBackgroundForWeather(); // Apply visual boost effects to weather-enhanced elements applyWeatherBoostEffects(); } // Function to get weather color function getWeatherColor(weather) { switch (weather) { case 'rainy': return 0x4169E1; // Royal blue case 'drought': return 0xFF4500; // Orange red case 'windy': return 0x87CEEB; // Sky blue case 'storm': return 0x9370DB; // Medium purple default: return 0xFFFFFF; } } // Function to check if element gets weather bonus function hasWeatherBonus(element) { if (!currentWeather || weatherRoundsLeft <= 0) { return false; } return weatherEffects[currentWeather].indexOf(element) !== -1; } // Function to apply boost visual effects to weather-enhanced elements function applyWeatherBoostEffects() { for (var i = 0; i < elementButtons.length; i++) { var button = elementButtons[i]; var element = button.elementType; if (hasWeatherBonus(element)) { // Replace elementButton with boostedElementButton for visual enhancement var background = button.children[0]; // The button background is the first child console.log(background); if (background) { // Remove old background button.removeChild(background); // Add boosted background var boostedBackground = button.attachAsset('boostedElementButton', { anchorX: 0.5, anchorY: 0.5 }); // Move to back so icon and label stay on top button.setChildIndex(boostedBackground, 0); } // Boosted elements use boostedElementButton asset without scaling animation } else { // Replace boostedElementButton back with regular elementButton for non-boosted elements var background = button.children[0]; // The button background is the first child if (background && background.texture) { // Check if it's currently boosted and needs to be replaced var isCurrentlyBoosted = background.texture.baseTexture && background.texture.baseTexture.imageUrl && background.texture.baseTexture.imageUrl.includes('boostedElementButton'); if (isCurrentlyBoosted) { // Remove boosted background button.removeChild(background); // Add regular background var regularBackground = button.attachAsset('elementButton', { anchorX: 0.5, anchorY: 0.5 }); // Move to back so icon and label stay on top button.setChildIndex(regularBackground, 0); } } button.tint = 0xffffff; // Stop any existing scale tweens for non-boosted elements tween.stop(button, { scaleX: true, scaleY: true }); // Reset scale to normal without animation for non-boosted elements if (!button.isSelected && !button.isDisabled) { button.scaleX = 1.0; button.scaleY = 1.0; } } } } // Combo helper functions function getComboKey(combo) { if (combo.length !== 2) { return null; } var sorted = combo.slice().sort(); return sorted[0] + '+' + sorted[1]; } function getComboEffect(combo) { var key = getComboKey(combo); return comboEffects[key] || null; } function updateComboDisplay() { // Clear existing combo elements for (var i = comboDisplay.children.length - 1; i >= 0; i--) { comboDisplay.removeChild(comboDisplay.children[i]); } comboDisplay.setText(''); if (playerCombo.length === 0) { // No combo } else if (playerCombo.length === 1) { comboDisplay.setText('Your Combo'); var icon1 = LK.getAsset(playerCombo[0], { anchorX: 0.5, anchorY: 0.5, scaleX: 0.9, scaleY: 0.9 }); icon1.x = -180; icon1.y = 130; comboDisplay.addChild(icon1); var plusText = new Text2(' + ?', { size: 60, fill: 0xFFFFFF, font: "Trebuchet MS, Arial, sans-serif", stroke: 0x000000, strokeThickness: 6 }); plusText.x = 0; plusText.y = 130; plusText.anchor.set(0.5, 0.5); comboDisplay.addChild(plusText); } else if (playerCombo.length === 2) { var effect = getComboEffect(playerCombo); if (effect) { comboDisplay.setText('Your Combo: ' + effect.name); comboDisplay.tint = 0x00FF00; // Green for special combo } else { comboDisplay.setText('Your Combo'); comboDisplay.tint = 0xFFD700; // Gold for normal combo } var icon1 = LK.getAsset(playerCombo[0], { anchorX: 0.5, anchorY: 0.5, scaleX: 0.9, scaleY: 0.9 }); icon1.x = -180; icon1.y = effect ? 130 : 130; comboDisplay.addChild(icon1); var plusText = new Text2(' + ', { size: 60, fill: 0xFFFFFF, font: "Trebuchet MS, Arial, sans-serif", stroke: 0x000000, strokeThickness: 6 }); plusText.x = 0; plusText.y = effect ? 130 : 130; plusText.anchor.set(0.5, 0.5); comboDisplay.addChild(plusText); var icon2 = LK.getAsset(playerCombo[1], { anchorX: 0.5, anchorY: 0.5, scaleX: 0.9, scaleY: 0.9 }); icon2.x = 180; icon2.y = effect ? 130 : 130; comboDisplay.addChild(icon2); } } function updateAIComboDisplay() { // Clear existing combo elements for (var i = aiComboDisplay.children.length - 1; i >= 0; i--) { aiComboDisplay.removeChild(aiComboDisplay.children[i]); } aiComboDisplay.setText(''); if (aiCombo.length === 0) { // No combo } else if (aiCombo.length === 1) { aiComboDisplay.setText('AI Combo'); var icon1 = LK.getAsset(aiCombo[0], { anchorX: 0.5, anchorY: 0.5, scaleX: 0.9, scaleY: 0.9 }); icon1.x = -180; icon1.y = 130; aiComboDisplay.addChild(icon1); var plusText = new Text2(' + ?', { size: 60, fill: 0xFFFFFF, font: "Trebuchet MS, Arial, sans-serif", stroke: 0x000000, strokeThickness: 6 }); plusText.x = 0; plusText.y = 130; plusText.anchor.set(0.5, 0.5); aiComboDisplay.addChild(plusText); } else if (aiCombo.length === 2) { var effect = getComboEffect(aiCombo); if (effect) { aiComboDisplay.setText('AI Combo: ' + effect.name); aiComboDisplay.tint = 0x00FF00; // Green for special combo } else { aiComboDisplay.setText('AI Combo'); aiComboDisplay.tint = 0xFFD700; // Gold for normal combo } var icon1 = LK.getAsset(aiCombo[0], { anchorX: 0.5, anchorY: 0.5, scaleX: 0.9, scaleY: 0.9 }); icon1.x = -180; icon1.y = effect ? 130 : 130; aiComboDisplay.addChild(icon1); var plusText = new Text2(' + ', { size: 60, fill: 0xFFFFFF, font: "Trebuchet MS, Arial, sans-serif", stroke: 0x000000, strokeThickness: 6 }); plusText.x = 0; plusText.y = effect ? 130 : 130; plusText.anchor.set(0.5, 0.5); aiComboDisplay.addChild(plusText); var icon2 = LK.getAsset(aiCombo[1], { anchorX: 0.5, anchorY: 0.5, scaleX: 0.9, scaleY: 0.9 }); icon2.x = 180; icon2.y = effect ? 130 : 130; aiComboDisplay.addChild(icon2); } } // Text positioning parameter - distance to move text toward wheel center var textOffsetTowardCenter = 160; // Adjustable parameter for text positioning // UI elements var titleText = new Text2('ULTIMATE ELEMENTS SHOWDOWN', { size: 48, fill: 0xFFFFFF, font: "Trebuchet MS, Arial, sans-serif", stroke: 0x000000, strokeThickness: 4 }); titleText.anchor.set(0.5, 0); LK.gui.top.addChild(titleText); titleText.y = 50; var instructionText = new Text2('Choose your element', { size: 32, fill: 0xCCCCCC, font: "Trebuchet MS, Arial, sans-serif", stroke: 0x000000, strokeThickness: 3 }); instructionText.anchor.set(0.5, 0.5); game.addChild(instructionText); instructionText.x = 1024; instructionText.y = 400; var playerLifeText = new Text2('Player Life: 100', { size: 36, fill: 0x00FF00, font: "Trebuchet MS, Arial, sans-serif", stroke: 0x000000, strokeThickness: 3 }); playerLifeText.anchor.set(1, 0); LK.gui.topRight.addChild(playerLifeText); playerLifeText.x = -20; playerLifeText.y = 20; var aiLifeText = new Text2('AI Life: 100', { size: 32, fill: 0xFF0000, font: "Trebuchet MS, Arial, sans-serif", stroke: 0x000000, strokeThickness: 3 }); aiLifeText.anchor.set(1, 0); LK.gui.topRight.addChild(aiLifeText); aiLifeText.x = -20; aiLifeText.y = 70; var weatherText = new Text2('', { size: 28, fill: 0x87CEEB, font: "Trebuchet MS, Arial, sans-serif", stroke: 0x000000, strokeThickness: 3 }); weatherText.anchor.set(1, 0); LK.gui.topRight.addChild(weatherText); weatherText.x = -20; weatherText.y = 120; // Position under Wins text // Combo display in center of wheel comboDisplay = new Text2('', { size: 72, fill: 0xFFD700, font: "Trebuchet MS, Arial, sans-serif", stroke: 0xFFFFFF, strokeThickness: 6 }); comboDisplay.anchor.set(0.5, 0.5); game.addChild(comboDisplay); comboDisplay.x = 1024; comboDisplay.y = 1000; // AI combo display widget var aiComboDisplay = new Text2('', { size: 72, fill: 0xFFD700, font: "Trebuchet MS, Arial, sans-serif", stroke: 0xFFFFFF, strokeThickness: 6 }); aiComboDisplay.anchor.set(0.5, 0.5); game.addChild(aiComboDisplay); aiComboDisplay.x = 1024; aiComboDisplay.y = 1400; // 400 pixels down from player combo display at y: 1000 // Create element selection grid function createElementButtons() { var centerX = 1024; var centerY = 1400; var radius = 800; // Create container for victory arrows (behind wheel elements) var arrowsContainer = new Container(); arrowsContainer.x = centerX; arrowsContainer.y = centerY; game.addChild(arrowsContainer); // Create wheel container for spinning animation wheelContainer = new Container(); wheelContainer.x = centerX; wheelContainer.y = centerY; game.addChild(wheelContainer); for (var i = 0; i < elements.length; i++) { var angle = i / elements.length * Math.PI * 2 - Math.PI / 2; var x = Math.cos(angle) * radius; var y = Math.sin(angle) * radius; var button = wheelContainer.addChild(new ElementButton(elements[i], i)); button.x = x; button.y = y; button.positionTextTowardCenter(0, 0); // Use wheel center as reference // Store original label position var label = button.children[button.children.length - 1]; if (label && label.setText) { button.originalLabelX = label.x; button.originalLabelY = label.y; } elementButtons.push(button); } } // Global variables for confirmation buttons var confirmationContainer = null; var useAsComboButton = null; var useAsSingleButton = null; // Create confirmation buttons for combo/single choice function createConfirmationButtons(selectedElement) { // Clean up existing confirmation buttons if (confirmationContainer) { confirmationContainer.destroy(); confirmationContainer = null; } // Create container for confirmation popup centered in the wheel confirmationContainer = new Container(); confirmationContainer.x = 1024; // Center horizontally confirmationContainer.y = 1000; // Center at wheel position game.addChild(confirmationContainer); // Create white background popup var popupBackground = confirmationContainer.attachAsset('popup', { anchorX: 0.5, anchorY: 0.5, scaleX: 2.5, scaleY: 2.0, alpha: 0 }); confirmationContainer.addChild(popupBackground); // Create "Use as Single" button useAsSingleButton = confirmationContainer.attachAsset('button', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.5, scaleY: 1 }); useAsSingleButton.x = 0; useAsSingleButton.y = 275; useAsSingleButton.tint = 0xFFD700; // Gold tint var singleText = new Text2('USE 1 ELEMENT', { size: 25, fill: 0x000000, font: "Trebuchet MS, Arial, sans-serif", stroke: 0x000000, strokeThickness: 1 }); singleText.anchor.set(0.5, 0.5); singleText.x = 0; singleText.y = 275; confirmationContainer.addChild(singleText); // Title text removed - combo display will be in center instead // Add click handlers useAsSingleButton.down = function (x, y, obj) { LK.getSound('select').play(); handleComboChoice(selectedElement, false); }; // Animate buttons in confirmationContainer.alpha = 0; tween(confirmationContainer, { alpha: 1 }, { duration: 300 }); } // Handle combo/single choice function handleComboChoice(selectedElement, isCombo) { // Clean up confirmation buttons if (confirmationContainer) { tween(confirmationContainer, { alpha: 0 }, { duration: 200, onFinish: function onFinish() { confirmationContainer.destroy(); confirmationContainer = null; } }); } if (isCombo) { // Player wants to make a combo - wait for second element selection instructionText.setText('Choose second element for combo'); // Keep the first element in combo array, wait for second selection } else { // Player wants to use single element playerElement = selectedElement; playerCombo = [selectedElement]; // Keep as single element combo updateComboDisplay(); // Reset aiElement and combo when starting new selection aiElement = null; aiCombo = []; aiComboSpins = 0; // Update button states for (var i = 0; i < elementButtons.length; i++) { elementButtons[i].setSelected(false); } // Start wheel spinning animation startWheelSpin(); } } // Select element function function selectElement(elementType) { if (gameState !== 'selection') { return; } // Check if element has already been used by player if (usedPlayerElements.indexOf(elementType) !== -1) { return; // Don't allow selection of already used elements } // Check if element is already in current player combo if (playerCombo.indexOf(elementType) !== -1) { return; // Don't allow selecting same element twice in combo } // Handle combo selection if (playerCombo.length === 0) { // First element selection playerCombo.push(elementType); updateComboDisplay(); // Update button states to show first selection for (var i = 0; i < elementButtons.length; i++) { elementButtons[i].setSelected(elementButtons[i].elementType === elementType); } // Create confirmation buttons createConfirmationButtons(elementType); } else if (playerCombo.length === 1) { // Second element selection (only reached if player chose combo option) playerCombo.push(elementType); playerElement = null; // Use combo instead of single element updateComboDisplay(); // Clean up confirmation buttons when second element is selected if (confirmationContainer) { tween(confirmationContainer, { alpha: 0 }, { duration: 200, onFinish: function onFinish() { confirmationContainer.destroy(); confirmationContainer = null; } }); } // Reset aiElement and combo when starting new selection aiElement = null; aiCombo = []; aiComboSpins = 0; // Update button states for (var i = 0; i < elementButtons.length; i++) { elementButtons[i].setSelected(false); } // Start wheel spinning animation startWheelSpin(); } } // Start wheel spinning animation function startWheelSpin() { gameState = 'spinning'; isWheelSpinning = true; // Determine if AI should use combo var shouldUseCombo = Math.random() < 0.4; // 40% chance for AI to use combo if (shouldUseCombo && aiCombo.length === 0) { instructionText.setText('AI is choosing combo...'); aiComboSpins = 1; // AI will spin twice for combo } else if (aiComboSpins === 1) { instructionText.setText('AI choosing second element...'); } else { instructionText.setText('AI is choosing...'); } // Add triangle pointing down behind the "AI is choosing" text var triangle = LK.getAsset('marker', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.8 }); triangle.tint = 0xFFFFFF; triangle.rotation = Math.PI / 2; // Rotate 90 degrees to point down triangle.x = 1024; // Center horizontally triangle.y = 475; // Position below the instruction text triangle.alpha = 1; // Show triangle immediately when AI is spinning game.addChild(triangle); // Store triangle reference for cleanup instructionText.triangle = triangle; // Hide victory arrows during spinning for (var i = 0; i < victoryArrows.length; i++) { tween(victoryArrows[i], { alpha: 0 }, { duration: 300 }); } // Hide element labels during spinning for (var i = 0; i < elementButtons.length; i++) { var button = elementButtons[i]; var label = button.children[button.children.length - 1]; // Label is the last child if (label && label.setText) { label.alpha = 0; // Immediately hide labels } } // Get available elements for AI (not disabled and not already in current AI combo) var availableElements = []; for (var i = 0; i < elementButtons.length; i++) { var elementType = elementButtons[i].elementType; if (!elementButtons[i].isDisabled && aiCombo.indexOf(elementType) === -1) { availableElements.push(elementType); } } // Calculate how many spins we need to ensure we land on an available element var spinAmount = 3 + Math.random() * 3; // 3-6 full rotations var baseRotation = spinAmount * Math.PI * 2; // Choose a random available element to land on var targetElement = availableElements[Math.floor(Math.random() * availableElements.length)]; var targetIndex = elements.indexOf(targetElement); // Calculate angle per element var anglePerElement = Math.PI * 2 / elements.length; // Calculate the rotation needed to put target element at top // Rock (index 0) starts at -PI/2, so target element should be at -PI/2 var targetAngleFromStart = targetIndex * anglePerElement; var rotationToTarget = -targetAngleFromStart; // Negative because wheel rotates clockwise // Final rotation combines base spins with precise positioning var finalRotation = baseRotation + rotationToTarget; // Ensure we stop at exact element positions by rounding to nearest element angle var exactElementPosition = Math.round(finalRotation / anglePerElement) * anglePerElement; finalRotation = exactElementPosition; // Reset wheel rotation for animation wheelContainer.rotation = 0; // Function to check if wheel stopped on disabled element and continue spinning function checkAndContinueSpinning() { // Get the current top element var currentTopElement = getTopElement(); // Find the button for this element var topButton = null; for (var i = 0; i < elementButtons.length; i++) { if (elementButtons[i].elementType === currentTopElement) { topButton = elementButtons[i]; break; } } // If the top element is disabled, continue spinning to next available element if (topButton && topButton.isDisabled) { // Find the next non-disabled element var nextAvailableIndex = -1; var currentIndex = elements.indexOf(currentTopElement); for (var step = 1; step < elements.length; step++) { var checkIndex = (currentIndex + step) % elements.length; var checkElement = elements[checkIndex]; var checkButton = null; for (var i = 0; i < elementButtons.length; i++) { if (elementButtons[i].elementType === checkElement) { checkButton = elementButtons[i]; break; } } if (checkButton && !checkButton.isDisabled) { nextAvailableIndex = checkIndex; break; } } if (nextAvailableIndex !== -1) { // Calculate additional rotation needed to reach next available element var additionalSteps = (nextAvailableIndex - currentIndex + elements.length) % elements.length; var additionalRotation = additionalSteps * anglePerElement; // Continue spinning to the next available element tween(wheelContainer, { rotation: wheelContainer.rotation - additionalRotation }, { duration: 1000, easing: tween.easeOut, onFinish: function onFinish() { // Check again in case we need to continue further checkAndContinueSpinning(); } }); return; } } // If we reach here, the wheel has stopped on a valid element if (aiComboSpins === 1) { // AI is building a combo - this is first element // Check if element is already in AI combo (should not happen, but safety check) if (aiCombo.indexOf(currentTopElement) === -1) { aiCombo.push(currentTopElement); } aiComboSpins = 2; updateAIComboDisplay(); // Start spinning again for second element LK.setTimeout(function () { startWheelSpin(); }, 1000); } else if (aiComboSpins === 2) { // AI is completing combo - this is second element // Check if element is already in AI combo to prevent duplicates if (aiCombo.indexOf(currentTopElement) === -1) { aiCombo.push(currentTopElement); aiComboSpins = 0; isWheelSpinning = false; updateAIComboDisplay(); // Start battle after wheel stops LK.setTimeout(function () { startBattle(); }, 2000); // Wait 2 seconds before VS screen } else { // AI selected same element twice, spin again for different element LK.setTimeout(function () { startWheelSpin(); }, 1000); } } else { // AI using single element isWheelSpinning = false; aiElement = currentTopElement; updateAIComboDisplay(); // Start battle after wheel stops LK.setTimeout(function () { startBattle(); }, 2000); // Wait 2 seconds before VS screen } } // Animate wheel spinning tween(wheelContainer, { rotation: finalRotation }, { duration: 2000 + Math.random() * 1000, // 2-3 seconds easing: tween.easeOut, onFinish: function onFinish() { // Check if we need to continue spinning checkAndContinueSpinning(); } }); } // AI element selection with intelligent combo avoidance function getAIElement() { // Get available elements (not used by AI yet) var availableElements = []; for (var i = 0; i < elements.length; i++) { if (usedAIElements.indexOf(elements[i]) === -1) { availableElements.push(elements[i]); } } // If no available elements, use all elements (shouldn't happen in normal gameplay) if (availableElements.length === 0) { availableElements = elements.slice(); } // AI intelligently avoids critical combos (registered combo effects) var safeElements = []; var criticalElements = []; for (var i = 0; i < availableElements.length; i++) { var element = availableElements[i]; var wouldCreateCriticalCombo = false; // Check if this element would create a critical combo with existing AI combo elements if (aiCombo.length > 0) { var testCombo = aiCombo.slice(); testCombo.push(element); if (getComboEffect(testCombo)) { wouldCreateCriticalCombo = true; } } if (wouldCreateCriticalCombo) { criticalElements.push(element); } else { safeElements.push(element); } } // AI prefers safe elements (80% chance to avoid critical combos) var elementsToChooseFrom = safeElements.length > 0 && Math.random() < 0.8 ? safeElements : availableElements; // Basic AI that becomes more strategic with difficulty if (difficultyLevel === 1) { // Random selection from safe elements return elementsToChooseFrom[Math.floor(Math.random() * elementsToChooseFrom.length)]; } else if (difficultyLevel === 2) { // 30% chance to counter player's last choice if (Math.random() < 0.3 && playerElement) { var counters = []; for (var i = 0; i < elementsToChooseFrom.length; i++) { if (defeats[elementsToChooseFrom[i]] && defeats[elementsToChooseFrom[i]].indexOf(playerElement) !== -1) { counters.push(elementsToChooseFrom[i]); } } if (counters.length > 0) { return counters[Math.floor(Math.random() * counters.length)]; } } return elementsToChooseFrom[Math.floor(Math.random() * elementsToChooseFrom.length)]; } else { // 50% chance to counter player's choice if (Math.random() < 0.5 && playerElement) { var counters = []; for (var i = 0; i < elementsToChooseFrom.length; i++) { if (defeats[elementsToChooseFrom[i]] && defeats[elementsToChooseFrom[i]].indexOf(playerElement) !== -1) { counters.push(elementsToChooseFrom[i]); } } if (counters.length > 0) { return counters[Math.floor(Math.random() * counters.length)]; } } return elementsToChooseFrom[Math.floor(Math.random() * elementsToChooseFrom.length)]; } } // Start battle phase function startBattle() { gameState = 'battle'; // aiElement is already set by wheel spin, only get it if not set if (!aiElement && aiCombo.length === 0) { aiElement = getAIElement(); } // Track used elements if (playerElement && usedPlayerElements.indexOf(playerElement) === -1) { usedPlayerElements.push(playerElement); } if (playerCombo.length > 0) { for (var i = 0; i < playerCombo.length; i++) { if (usedPlayerElements.indexOf(playerCombo[i]) === -1) { usedPlayerElements.push(playerCombo[i]); } } } if (aiElement && usedAIElements.indexOf(aiElement) === -1) { usedAIElements.push(aiElement); } if (aiCombo.length > 0) { for (var i = 0; i < aiCombo.length; i++) { if (usedAIElements.indexOf(aiCombo[i]) === -1) { usedAIElements.push(aiCombo[i]); } } } // Reset hover state hoveredButton = null; // Hide victory arrows during battle for (var i = 0; i < victoryArrows.length; i++) { tween(victoryArrows[i], { alpha: 0 }, { duration: 300 }); } // Hide combo displays during battle if (comboDisplay) { tween(comboDisplay, { alpha: 0 }, { duration: 300 }); } // Hide AI combo display during battle if (aiComboDisplay) { tween(aiComboDisplay, { alpha: 0 }, { duration: 300 }); } // Hide triangle if it exists if (instructionText.triangle) { instructionText.triangle.alpha = 0; // Hide triangle immediately in VS screen tween(instructionText.triangle, { alpha: 0 }, { duration: 300, onFinish: function onFinish() { instructionText.triangle.destroy(); instructionText.triangle = null; } }); } // Hide selection elements and disable them for (var i = 0; i < elementButtons.length; i++) { elementButtons[i].setDisabled(true); tween(elementButtons[i], { alpha: 0 }, { duration: 300 }); } instructionText.setText('BATTLE!'); // Create battle elements var playerDisplayElement = playerElement || playerCombo[0] || 'unknown'; var aiDisplayElement = aiElement || aiCombo[0] || 'unknown'; playerBattleElement = game.addChild(new BattleElement(playerDisplayElement, true)); playerBattleElement.x = 400; playerBattleElement.y = 1100; playerBattleElement.alpha = 0; // Add second element icon and label for player combo if (playerCombo.length === 2) { var playerSecondIcon = LK.getAsset(playerCombo[1], { anchorX: 0.5, anchorY: 0.5, scaleX: 0.6, scaleY: 0.6 }); playerSecondIcon.x = 100; playerSecondIcon.y = -80; playerBattleElement.addChild(playerSecondIcon); playerBattleElement.addSecondElementLabel(playerCombo[1]); } aiBattleElement = game.addChild(new BattleElement(aiDisplayElement, false)); aiBattleElement.x = 1648; aiBattleElement.y = 1100; aiBattleElement.alpha = 0; // Add second element icon and label for AI combo if (aiCombo.length === 2) { var aiSecondIcon = LK.getAsset(aiCombo[1], { anchorX: 0.5, anchorY: 0.5, scaleX: 0.6, scaleY: 0.6 }); aiSecondIcon.x = -80; aiSecondIcon.y = -100; aiBattleElement.addChild(aiSecondIcon); aiBattleElement.addSecondElementLabel(aiCombo[1]); } // Animate battle elements in tween(playerBattleElement, { alpha: 1, x: 512 }, { duration: 500 }); tween(aiBattleElement, { alpha: 1, x: 1536 }, { duration: 500 }); // Add battle instruction text vsText = new Text2('BATTLE!', { size: 120, fill: 0xFF6B35, font: "Trebuchet MS, Arial, sans-serif", stroke: 0x000000, strokeThickness: 8 }); vsText.anchor.set(0.5, 0.5); vsText.x = 1024; vsText.y = 1100; vsText.alpha = 0; game.addChild(vsText); // Create battle result text (separate from BATTLE! text) var battleResultText = new Text2('', { size: 100, fill: 0xFFFFFF, font: "Trebuchet MS, Arial, sans-serif", stroke: 0x000000, strokeThickness: 6 }); battleResultText.anchor.set(0.5, 0.5); battleResultText.x = 1024; battleResultText.y = 1100; battleResultText.alpha = 0; game.addChild(battleResultText); tween(vsText, { alpha: 1, scaleX: 1.2, scaleY: 1.2 }, { duration: 300, onFinish: function onFinish() { LK.getSound('battle').play(); // Start battle timer battleTimer = 0; } }); } // Get action keyword for how one element defeats another function getActionKeyword(winner, loser) { if (actionKeywords[winner] && actionKeywords[winner][loser]) { return actionKeywords[winner][loser]; } return 'defeats'; } // Check battle result function checkBattleResult() { // Determine what elements are actually battling var playerBattleElements = playerElement ? [playerElement] : playerCombo; var aiBattleElements = aiElement ? [aiElement] : aiCombo; // Check for combo effects var playerComboEffect = playerCombo.length === 2 ? getComboEffect(playerCombo) : null; var aiComboEffect = aiCombo.length === 2 ? getComboEffect(aiCombo) : null; // Calculate wins using combo logic var playerWins = false; var aiWins = false; // Player vs AI battle logic for (var i = 0; i < playerBattleElements.length && !playerWins; i++) { for (var j = 0; j < aiBattleElements.length && !playerWins; j++) { if (defeats[playerBattleElements[i]] && defeats[playerBattleElements[i]].indexOf(aiBattleElements[j]) !== -1) { playerWins = true; } // Check combo extra defeats if (playerComboEffect && playerComboEffect.defeatsExtra.indexOf(aiBattleElements[j]) !== -1) { playerWins = true; } } } for (var i = 0; i < aiBattleElements.length && !aiWins; i++) { for (var j = 0; j < playerBattleElements.length && !aiWins; j++) { if (defeats[aiBattleElements[i]] && defeats[aiBattleElements[i]].indexOf(playerBattleElements[j]) !== -1) { aiWins = true; } // Check combo extra defeats if (aiComboEffect && aiComboEffect.defeatsExtra.indexOf(playerBattleElements[j]) !== -1) { aiWins = true; } } } // Apply weather effects var playerHasBonus = false; var aiHasBonus = false; for (var i = 0; i < playerBattleElements.length; i++) { if (hasWeatherBonus(playerBattleElements[i])) { playerHasBonus = true; break; } } for (var i = 0; i < aiBattleElements.length; i++) { if (hasWeatherBonus(aiBattleElements[i])) { aiHasBonus = true; break; } } // Weather bonus can override normal defeat relationships if (playerHasBonus && !aiHasBonus) { // Player gets weather advantage if (!playerWins && !aiWins) { // In a tie, weather bonus wins return 'player'; } // If AI would normally win, weather bonus creates a tie instead if (aiWins && !playerWins) { return 'tie'; } } else if (aiHasBonus && !playerHasBonus) { // AI gets weather advantage if (!playerWins && !aiWins) { // In a tie, weather bonus wins return 'ai'; } // If player would normally win, weather bonus creates a tie instead if (playerWins && !aiWins) { return 'tie'; } } // Normal battle logic if no weather advantage or both have advantage if (playerWins) { return 'player'; } else if (aiWins) { return 'ai'; } else { return 'tie'; } } // Show battle result with life system and critical mechanics function showBattleResult() { gameState = 'result'; var result = checkBattleResult(); // Determine if combos are critical (registered) or failures (unregistered) var playerComboEffect = playerCombo.length === 2 ? getComboEffect(playerCombo) : null; var aiComboEffect = aiCombo.length === 2 ? getComboEffect(aiCombo) : null; var playerIsCritical = playerCombo.length === 2 && playerComboEffect !== null; var playerIsFailure = playerCombo.length === 2 && playerComboEffect === null; var aiIsCritical = aiCombo.length === 2 && aiComboEffect !== null; var aiIsFailure = aiCombo.length === 2 && aiComboEffect === null; var baseDamage = 10; var playerDamage = baseDamage; var aiDamage = baseDamage; // Apply critical effects if (playerIsCritical) { playerDamage *= 2; // Critical success - double damage to opponent } else if (playerIsFailure) { // Critical failure - double damage to self (will be applied if player loses) playerDamage *= 2; } if (aiIsCritical) { aiDamage *= 2; // Critical success - double damage to opponent } else if (aiIsFailure) { // Critical failure - double damage to self (will be applied if AI loses) aiDamage *= 2; } if (result === 'player') { LK.getSound('win').play(); playerBattleElement.playWinAnimation(); aiBattleElement.playLoseAnimation(); // Player wins - damage to AI var damage = playerIsCritical ? playerDamage : baseDamage; aiLife -= damage; if (aiLife < 0) { aiLife = 0; } // Create result text var playerDesc = playerElement ? playerElement.toUpperCase() : playerComboEffect ? playerComboEffect.name : playerCombo.join(' + ').toUpperCase(); var aiDesc = aiElement ? aiElement.toUpperCase() : aiCombo.length === 2 ? aiCombo.join(' + ').toUpperCase() : 'AI COMBO'; var actionWord = 'defeats'; if (playerElement && aiElement) { actionWord = getActionKeyword(playerElement, aiElement); } var resultText = playerDesc + ' ' + actionWord + ' ' + aiDesc + '!\nYOU WIN! -' + damage + ' AI Life'; if (playerIsCritical) { resultText += '\nCRITICAL SUCCESS!'; } battleResultText.setText(resultText); battleResultText.tint = 0x00ff00; battleResultText.alpha = 1; // Check for AI death if (aiLife <= 0) { LK.showYouWin(); return; } } else if (result === 'ai') { LK.getSound('lose').play(); playerBattleElement.playLoseAnimation(); aiBattleElement.playWinAnimation(); // AI wins - damage to player var damage = aiIsCritical ? aiDamage : baseDamage; playerLife -= damage; if (playerLife < 0) { playerLife = 0; } var aiDesc = aiElement ? aiElement.toUpperCase() : aiCombo.length === 2 ? aiCombo.join(' + ').toUpperCase() : 'AI'; var playerDesc = playerElement ? playerElement.toUpperCase() : playerCombo.length === 2 ? playerCombo.join(' + ').toUpperCase() : 'PLAYER'; var actionWord = 'defeats'; if (aiElement && playerElement) { actionWord = getActionKeyword(aiElement, playerElement); } var resultText = aiDesc + ' ' + actionWord + ' ' + playerDesc + '!\nYOU LOSE! -' + damage + ' Life'; if (aiIsCritical) { resultText += '\nAI CRITICAL SUCCESS!'; } battleResultText.setText(resultText); battleResultText.tint = 0xff0000; battleResultText.alpha = 1; // Check for player death if (playerLife <= 0) { LK.showGameOver(); return; } } else { // Handle critical failures in ties if (playerIsFailure && !aiIsFailure) { // Player critical failure - damage to player playerLife -= playerDamage; if (playerLife < 0) { playerLife = 0; } battleResultText.setText('TIE!\nCRITICAL FAILURE! -' + playerDamage + ' Life'); battleResultText.tint = 0xff0000; battleResultText.alpha = 1; if (playerLife <= 0) { LK.showGameOver(); return; } } else if (aiIsFailure && !playerIsFailure) { // AI critical failure - damage to AI aiLife -= aiDamage; if (aiLife < 0) { aiLife = 0; } battleResultText.setText('TIE!\nAI CRITICAL FAILURE! -' + aiDamage + ' AI Life'); battleResultText.tint = 0x00ff00; battleResultText.alpha = 1; if (aiLife <= 0) { LK.showYouWin(); return; } } else if (playerIsFailure && aiIsFailure) { // Both critical failures playerLife -= playerDamage; aiLife -= aiDamage; if (playerLife < 0) { playerLife = 0; } if (aiLife < 0) { aiLife = 0; } battleResultText.setText('TIE!\nBOTH CRITICAL FAILURES!'); battleResultText.tint = 0xffff00; battleResultText.alpha = 1; if (playerLife <= 0 && aiLife <= 0) { LK.showGameOver(); // Player dies first in simultaneous death return; } else if (playerLife <= 0) { LK.showGameOver(); return; } else if (aiLife <= 0) { LK.showYouWin(); return; } } else { battleResultText.setText('TIE!'); battleResultText.tint = 0xffff00; battleResultText.alpha = 1; } } // Update UI playerLifeText.setText('Player Life: ' + playerLife); aiLifeText.setText('AI Life: ' + aiLife); // Update weather system if (weatherRoundsLeft > 0) { weatherRoundsLeft--; updateWeatherDisplay(); if (weatherRoundsLeft === 0) { currentWeather = null; updateWeatherDisplay(); // Update display when weather ends } } else { // 30% chance to start new weather when no weather is active if (Math.random() < 0.3) { startNewWeather(); } } // Return to selection after delay LK.setTimeout(function () { resetForNextRound(); }, 2000); } // Create victory arrow function function createVictoryArrow(losingElement, winningElement) { // Find element indices var losingIndex = elements.indexOf(losingElement); var winningIndex = elements.indexOf(winningElement); if (losingIndex === -1 || winningIndex === -1) { return; } // Calculate initial static positions (same as in createElementButtons) var centerX = 1024; var centerY = 1400; var radius = 800; // Calculate losing element position var losingAngle = losingIndex / elements.length * Math.PI * 2 - Math.PI / 2; var losingX = centerX + Math.cos(losingAngle) * radius; var losingY = centerY + Math.sin(losingAngle) * radius; // Calculate winning element position var winningAngle = winningIndex / elements.length * Math.PI * 2 - Math.PI / 2; var winningX = centerX + Math.cos(winningAngle) * radius; var winningY = centerY + Math.sin(winningAngle) * radius; // Create bezier curve points using static positions // Adjust for arrows container offset var startX = losingX - centerX; var startY = losingY - centerY; var endX = winningX - centerX; var endY = winningY - centerY; var controlX = 0; // Center relative to arrows container var controlY = 0; // Create container for the arrow var arrowContainer = new Container(); // Find the arrows container (first child of game that's a Container) var arrowsContainer = null; for (var i = 0; i < game.children.length; i++) { if (game.children[i].constructor === Container && game.children[i] !== wheelContainer) { arrowsContainer = game.children[i]; break; } } if (arrowsContainer) { arrowsContainer.addChild(arrowContainer); } else { game.addChild(arrowContainer); } // Number of segments for the bezier curve var segments = 80; var halfSegments = segments / 2; // Create line segments for bezier curve for (var i = 0; i < segments; i++) { var t1 = i / segments; var t2 = (i + 1) / segments; // Calculate bezier points var x1 = (1 - t1) * (1 - t1) * startX + 2 * (1 - t1) * t1 * controlX + t1 * t1 * endX; var y1 = (1 - t1) * (1 - t1) * startY + 2 * (1 - t1) * t1 * controlY + t1 * t1 * endY; var x2 = (1 - t2) * (1 - t2) * startX + 2 * (1 - t2) * t2 * controlX + t2 * t2 * endX; var y2 = (1 - t2) * (1 - t2) * startY + 2 * (1 - t2) * t2 * controlY + t2 * t2 * endY; // Calculate angle and distance for this segment var dx = x2 - x1; var dy = y2 - y1; var distance = Math.sqrt(dx * dx + dy * dy); var angle = Math.atan2(dy, dx); // Create line segment var lineSegment = LK.getAsset('line', { anchorX: 0, anchorY: 0.5 }); arrowContainer.addChild(lineSegment); // Position and rotate the segment lineSegment.x = x1; lineSegment.y = y1; lineSegment.rotation = angle; lineSegment.width = distance; lineSegment.height = 8; // Line thickness // Color the segment - first half red, second half green if (i < halfSegments) { lineSegment.tint = 0xff0000; // Red for first half } else { lineSegment.tint = 0x00ff00; // Green for second half } } // Store arrow for cleanup victoryArrows.push(arrowContainer); // Animate arrow appearance arrowContainer.alpha = 0; tween(arrowContainer, { alpha: 1 }, { duration: 500 }); } // Reset for next round function resetForNextRound() { gameState = 'selection'; // Stop any ongoing wheel spinning animation if (wheelContainer) { tween.stop(wheelContainer, { rotation: true }); } // Reset spinning state isWheelSpinning = false; // Reset combo state for next round playerCombo = []; aiCombo = []; aiComboSpins = 0; updateComboDisplay(); updateAIComboDisplay(); // Don't reset aiElement to null immediately - we need it for victory arrows // aiElement will be reset when a new round actually starts // Reset wheel rotation and element rotations if (wheelContainer) { wheelContainer.rotation = 0; } // Reset all element button rotations to keep them upright for (var i = 0; i < elementButtons.length; i++) { elementButtons[i].rotation = 0; } // Clean up battle elements if (playerBattleElement) { playerBattleElement.destroy(); playerBattleElement = null; } if (aiBattleElement) { aiBattleElement.destroy(); aiBattleElement = null; } if (vsText) { vsText.destroy(); vsText = null; } if (battleResultText) { battleResultText.destroy(); battleResultText = null; } // Reset instruction text instructionText.setText('Choose first element for combo'); instructionText.tint = 0xcccccc; // Restore original font size instructionText.size = 32; // Clean up triangle if it exists if (instructionText.triangle) { instructionText.triangle.destroy(); instructionText.triangle = null; } // Clean up confirmation buttons if they exist if (confirmationContainer) { confirmationContainer.destroy(); confirmationContainer = null; } // Reset confirmation button references useAsComboButton = null; useAsSingleButton = null; // Create victory arrow if we have a battle result and both elements are valid var battleResult = checkBattleResult(); if (playerElement && aiElement && battleResult !== 'tie') { if (battleResult === 'player') { createVictoryArrow(aiElement, playerElement); } else if (battleResult === 'ai') { createVictoryArrow(playerElement, aiElement); } } // Show victory arrows again for (var i = 0; i < victoryArrows.length; i++) { tween(victoryArrows[i], { alpha: 1 }, { duration: 300 }); } // Show combo displays again after battle if (comboDisplay) { tween(comboDisplay, { alpha: 1 }, { duration: 300 }); } // Show AI combo display again after battle if (aiComboDisplay) { tween(aiComboDisplay, { alpha: 1 }, { duration: 300 }); } // Show selection elements and re-enable only unused ones for (var i = 0; i < elementButtons.length; i++) { elementButtons[i].setSelected(false); var elementType = elementButtons[i].elementType; var isUsed = usedPlayerElements.indexOf(elementType) !== -1 || usedAIElements.indexOf(elementType) !== -1; elementButtons[i].setDisabled(isUsed); tween(elementButtons[i], { alpha: 1 }, { duration: 300 }); // Show element labels again after returning from battle var button = elementButtons[i]; var label = button.children[button.children.length - 1]; // Label is the last child if (label && label.setText) { tween(label, { alpha: 1 }, { duration: 300 }); } } // Apply weather boost effects to visible elements applyWeatherBoostEffects(); // Reset battle timer battleTimer = 0; } // Game move handler for hover effects game.move = function (x, y, obj) { if (gameState !== 'selection') { return; } // Force triangle to always be hidden during user turn if (instructionText.triangle) { instructionText.triangle.alpha = 0; } var newHoveredButton = null; // Check which button is under the cursor for (var i = 0; i < elementButtons.length; i++) { var button = elementButtons[i]; // Convert game coordinates to wheel container space // Account for wheel container position (1024, 1400) var localX = x - wheelContainer.x; var localY = y - wheelContainer.y; // Calculate distance from cursor to button center var dx = localX - button.x; var dy = localY - button.y; var distance = Math.sqrt(dx * dx + dy * dy); // Use button's actual width/height to determine hit area (button is anchored at center) var hitRadius = 150; // Approximate radius for the button hit area if (distance < hitRadius) { newHoveredButton = button; break; } } // Handle hover state changes if (hoveredButton !== newHoveredButton) { // Handle leave event for previously hovered button if (hoveredButton && !hoveredButton.isSelected && !hoveredButton.isDisabled) { // Stop any existing scale tweens tween.stop(hoveredButton, { scaleX: true, scaleY: true }); // Scale back to normal tween(hoveredButton, { scaleX: 1.0, scaleY: 1.0 }, { duration: 150 }); } // Handle hover event for new button if (newHoveredButton && !newHoveredButton.isSelected && !newHoveredButton.isDisabled) { // Stop any existing scale tweens tween.stop(newHoveredButton, { scaleX: true, scaleY: true }); // Scale up on hover tween(newHoveredButton, { scaleX: 1.1, scaleY: 1.1 }, { duration: 150 }); } hoveredButton = newHoveredButton; } }; // Initialize game createElementButtons(); // Start with a random weather 50% of the time if (Math.random() < 0.5) { startNewWeather(); } else { // Start a new weather if none is active startNewWeather(); } // Game update loop game.update = function () { // Keep elements upright during wheel spinning if (isWheelSpinning && wheelContainer) { for (var i = 0; i < elementButtons.length; i++) { // Counter-rotate each element button to keep it upright elementButtons[i].rotation = -wheelContainer.rotation; // Restore original label position var button = elementButtons[i]; var label = button.children[button.children.length - 1]; if (label && label.setText && button.originalLabelX !== undefined) { label.x = button.originalLabelX; label.y = button.originalLabelY; } } } if (gameState === 'battle' && playerBattleElement && aiBattleElement) { battleTimer++; // Show result after 3 seconds if (battleTimer >= 180) { // 3 seconds at 60 FPS showBattleResult(); } } };
===================================================================
--- original.js
+++ change.js
@@ -1413,8 +1413,21 @@
vsText.x = 1024;
vsText.y = 1100;
vsText.alpha = 0;
game.addChild(vsText);
+ // Create battle result text (separate from BATTLE! text)
+ var battleResultText = new Text2('', {
+ size: 100,
+ fill: 0xFFFFFF,
+ font: "Trebuchet MS, Arial, sans-serif",
+ stroke: 0x000000,
+ strokeThickness: 6
+ });
+ battleResultText.anchor.set(0.5, 0.5);
+ battleResultText.x = 1024;
+ battleResultText.y = 1100;
+ battleResultText.alpha = 0;
+ game.addChild(battleResultText);
tween(vsText, {
alpha: 1,
scaleX: 1.2,
scaleY: 1.2
@@ -1561,10 +1574,11 @@
var resultText = playerDesc + ' ' + actionWord + ' ' + aiDesc + '!\nYOU WIN! -' + damage + ' AI Life';
if (playerIsCritical) {
resultText += '\nCRITICAL SUCCESS!';
}
- vsText.setText(resultText);
- vsText.tint = 0x00ff00;
+ battleResultText.setText(resultText);
+ battleResultText.tint = 0x00ff00;
+ battleResultText.alpha = 1;
// Check for AI death
if (aiLife <= 0) {
LK.showYouWin();
return;
@@ -1588,10 +1602,11 @@
var resultText = aiDesc + ' ' + actionWord + ' ' + playerDesc + '!\nYOU LOSE! -' + damage + ' Life';
if (aiIsCritical) {
resultText += '\nAI CRITICAL SUCCESS!';
}
- vsText.setText(resultText);
- vsText.tint = 0xff0000;
+ battleResultText.setText(resultText);
+ battleResultText.tint = 0xff0000;
+ battleResultText.alpha = 1;
// Check for player death
if (playerLife <= 0) {
LK.showGameOver();
return;
@@ -1603,10 +1618,11 @@
playerLife -= playerDamage;
if (playerLife < 0) {
playerLife = 0;
}
- vsText.setText('TIE!\nCRITICAL FAILURE! -' + playerDamage + ' Life');
- vsText.tint = 0xff0000;
+ battleResultText.setText('TIE!\nCRITICAL FAILURE! -' + playerDamage + ' Life');
+ battleResultText.tint = 0xff0000;
+ battleResultText.alpha = 1;
if (playerLife <= 0) {
LK.showGameOver();
return;
}
@@ -1615,10 +1631,11 @@
aiLife -= aiDamage;
if (aiLife < 0) {
aiLife = 0;
}
- vsText.setText('TIE!\nAI CRITICAL FAILURE! -' + aiDamage + ' AI Life');
- vsText.tint = 0x00ff00;
+ battleResultText.setText('TIE!\nAI CRITICAL FAILURE! -' + aiDamage + ' AI Life');
+ battleResultText.tint = 0x00ff00;
+ battleResultText.alpha = 1;
if (aiLife <= 0) {
LK.showYouWin();
return;
}
@@ -1631,10 +1648,11 @@
}
if (aiLife < 0) {
aiLife = 0;
}
- vsText.setText('TIE!\nBOTH CRITICAL FAILURES!');
- vsText.tint = 0xffff00;
+ battleResultText.setText('TIE!\nBOTH CRITICAL FAILURES!');
+ battleResultText.tint = 0xffff00;
+ battleResultText.alpha = 1;
if (playerLife <= 0 && aiLife <= 0) {
LK.showGameOver(); // Player dies first in simultaneous death
return;
} else if (playerLife <= 0) {
@@ -1644,10 +1662,11 @@
LK.showYouWin();
return;
}
} else {
- vsText.setText('TIE!');
- vsText.tint = 0xffff00;
+ battleResultText.setText('TIE!');
+ battleResultText.tint = 0xffff00;
+ battleResultText.alpha = 1;
}
}
// Update UI
playerLifeText.setText('Player Life: ' + playerLife);
@@ -1799,8 +1818,12 @@
if (vsText) {
vsText.destroy();
vsText = null;
}
+ if (battleResultText) {
+ battleResultText.destroy();
+ battleResultText = null;
+ }
// Reset instruction text
instructionText.setText('Choose first element for combo');
instructionText.tint = 0xcccccc;
// Restore original font size
A hand with its fingers symbolizing gas
Make the background darker (blue)
Make the bacgkground color darker(blue)
a triangle pointing down. In-Game asset. 2d. High contrast. No shadows
This place after a draught
This place in very windy conditions
This place but it's raining
This place but there is an electric storm
a popup frame, retro pixel style, rectangular. In-Game asset. 2d. High contrast. No shadows
A version of this frame that symbolizes that this button has boosted / improved power
a minimalistic pixel button, no text on it, just the buton. White.. In-Game asset. 2d. High contrast. No shadows
A win effect that will be over a round button and that will triger for some seconds after a win happens, scaling in x and y as an effect.. In-Game asset. 2d. High contrast. No shadows
Lose
The frame should be ice related too
The frame should be earth related too
The frame should be water related too
The frame should be wind too
A hand with its fingers symbolizing ash
A hand with its fingers symbolizing sun
A hand with its fingers symbolizing moon
A hand with a piece of leather
A hand with a piece of plastic
A hand with a piece of opaque plastic
A hand with its fingers symbolizing salt
Can you make this picture slightly lighter
Can you make this image lighter please? But not a lot lighter, just a little
A frame that symbolizes that the element inside is penalized, unboosted, has a minus to its effect. It should be shown in the frame, not inside! With some VFX effect
One drop of rain. In-Game asset. 2d. High contrast. No shadows
Yellow / Orange colour
wind. In-Game asset. 2d. High contrast. No shadows
A pixel style magician from Magicka who has an arc around him of elements to be casted (fire, water, ice, rock, etc). In-Game asset. 2d. High contrast. No shadows
Tint the wizard to blue
Make the black border of the start twice thicker
A '?' (question mark) symbol inside
A white shield. In-Game asset. 2d. High contrast. No shadows
background
Music
air
Music
storm
Music
rain
Music
draught
Music
rock
Sound effect
paper
Sound effect
scissors
Sound effect
fire
Sound effect
metal
Sound effect
water
Sound effect
airy
Sound effect
lightning
Sound effect
tree
Sound effect
gun
Sound effect
sponge
Sound effect
smoke
Sound effect
gas
Sound effect
ice
Sound effect
sand
Sound effect
oil
Sound effect
plastic
Sound effect
leather
Sound effect
sun
Sound effect
glass
Sound effect
cloth
Sound effect
ash
Sound effect
fungus
Sound effect
moon
Sound effect
salt
Sound effect
select
Sound effect
spinning
Sound effect
win
Sound effect