User prompt
Sun lightning is an unknown combo. Please fix.
User prompt
Play the music background by default. If a weather music plays (storm, draught, air, etc) it's ok - play them but them immediately come back to music background.
User prompt
There are unknown combos, as metal + salt. Please fix, all combos should have a name!
User prompt
Play salt sound when salt is selected
User prompt
Please play the sounds plastic, leather, sun, glass, cloth, ash, fungus, moon when the buttons are clicked.
User prompt
Ok I get "Unknown combo" - that should not happen. Please make names for all combos.
User prompt
Add thes enew elements and create new defeats, combo names, etc taken them ito account. Also create the assets for them. But don't add them to the wheel, the wheel will be always the same size of 16. But we will be just randomly using elements from this new pool that now will have more than 16. The new elements are: ash, fungus, sun, moon, salt, plastic, leather, cloth, glass
User prompt
Make the ai smarter, using the boosted elements if still available, and knowing at a 50% of the counter element of what the user has selected.
User prompt
Even if AI only selects 1 element, show anyway the AI COMBO widget with that element
User prompt
After the user clicks on an element, if the triangle marker is still shown, hide it.
User prompt
After the user clicks on an element, hdie the bezier lines.
User prompt
Triangle should leave separetely from instructionText.triangle. It should be an entity. And then: it disappears after the wheel starts to spin. triangle.alpha = 0 It appears again after the battle screen finishes: triangle.alpha = 1 ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Set alpha:0 to triangle marker when user turn.
User prompt
The marker triangle should NEVER be shown if it's the user's turn to select. It's only shown when the wheel is spinning during AI turn.
User prompt
Instead of "No weather conditions" show "No weather conditions (X rounds)" being X the remaining amount of rounds remaining
User prompt
No weather conditions can only stay maximum for 2 turns. Then mandatorely a season should start that is not "no weather conditions"
User prompt
There is a bug: sometimes no season is shown. If there is no season, which may be ok, show "No weather conditions" and the amount of rounds. Cancel any music then.
User prompt
Never tint of any color the combo names!
Code edit (1 edits merged)
Please save this source code
User prompt
imic bezier lines for individual elements but for combos. how? Just call the same logic for bezier lines what we have but from each element in user combo to each element in ai combo. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
GameOver: if player reaches 0 health or less. YouWin: if AI reaches 0 health or less
User prompt
If all the elementButtons are disabled, re-enabled them all.
User prompt
Bezier lines after combos ARE NOT SHOWN. They should be shown! After the battle screen when the combo is resolved. How? Calculate bezier line from each user element to each ai element. Show them next time in the wheel screen. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
You are showing combo bezier lines when I click the combo. NO! You only show bezier lines after the screen battle. And ALWAYS show bezier lines in wheel screen while it's NOT Spinning. After it's spinning, hdie them until after the battle screen. Make sure always at the user turn, when they are selecting the elements, PAST bezier lines are all showed, including combo bezier lines, but NEVER the current oones of the combo the user is selecting. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
The bezier lines are only shown after the battle, never on the same round they are selected. Also, make sure all bezier lines are shown when the battle screen finishes ↪💡 Consider importing and using the following plugins: @upit/tween.v1
/**** * 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 'rock': ['scissors', 'fire', 'ice', 'sponge', 'sand'], // Paper 'paper': ['rock', 'water', 'gas', 'gun', 'lightning'], // Scissors 'scissors': ['paper', 'sponge', 'gas', 'tree', 'air'], // Water 'water': ['fire', 'rock', 'metal', 'sponge', 'sand'], // Fire 'fire': ['paper', 'scissors', 'tree', 'gas', 'ice'], // Air 'air': ['fire', 'gas', 'paper', 'sand', 'smoke'], // Lightning 'lightning': ['water', 'air', 'sponge', 'metal', 'smoke'], // Tree 'tree': ['water', 'air', 'paper', 'sand', 'gun'], // Gun 'gun': ['rock', 'scissors', 'air', 'fire', 'metal'], // Sponge 'sponge': ['paper', 'water', 'fire', 'metal', 'gun'], // Smoke 'smoke': ['gun', 'tree', 'sponge', 'ice', 'oil'], // Gas 'gas': ['water', 'lightning', 'smoke', 'oil', 'metal'], // Metal 'metal': ['scissors', 'air', 'rock', 'ice', 'smoke'], // Ice 'ice': ['air', 'tree', 'scissors', 'water', 'lightning'], // Sand 'sand': ['fire', 'ice', 'lightning', 'sponge', 'smoke'], // Oil 'oil': ['sponge', 'gun', 'sand', 'tree', 'paper'] }; // Action keywords for how elements defeat others var actionKeywords = { 'rock': { 'scissors': 'crushes', 'fire': 'hardens against', 'ice': 'shatters', 'sponge': 'compacts', 'sand': 'forms' }, 'paper': { 'rock': 'wraps', 'water': 'absorbs', 'gas': 'captures', 'gun': 'covers', 'lightning': 'insulates against' }, 'scissors': { 'paper': 'cuts', 'sponge': 'snips', 'gas': 'ventilates', 'tree': 'trims', 'air': 'slices through' }, 'water': { 'fire': 'extinguishes', 'rock': 'erodes', 'metal': 'rusts', 'sponge': 'saturates', 'sand': 'washes away' }, 'fire': { 'paper': 'burns', 'scissors': 'melts', 'tree': 'incinerates', 'gas': 'ignites', 'ice': 'melts' }, 'air': { 'fire': 'feeds', 'gas': 'disperses', 'paper': 'carries', 'sand': 'blows', 'smoke': 'clears' }, 'lightning': { 'water': 'electrifies', 'air': 'ionizes', 'sponge': 'shocks', 'metal': 'conducts', 'smoke': 'disperses' }, 'tree': { 'water': 'absorbs', 'air': 'filters', 'paper': 'grows from', 'sand': 'roots in', 'gun': 'blocks' }, 'gun': { 'rock': 'shatters', 'scissors': 'shoots through', 'air': 'pushes', 'fire': 'ignites', 'metal': 'pierces' }, 'sponge': { 'paper': 'soaks', 'water': 'absorbs', 'fire': 'smothers', 'metal': 'corrodes', 'gun': 'dampens' }, 'smoke': { 'gun': 'jams', 'tree': 'obscures', 'sponge': 'clogs', 'ice': 'condenses', 'oil': 'mixes with' }, 'gas': { 'water': 'dissolves in', 'lightning': 'combusts with', 'smoke': 'displaces', 'oil': 'absorbs', 'metal': 'corrodes' }, 'metal': { 'scissors': 'dulls', 'air': 'oxidizes', 'rock': 'resists', 'ice': 'chills', 'smoke': 'tarnishes' }, 'ice': { 'air': 'freezes', 'tree': 'breaks', 'scissors': 'dulls', 'water': 'freezes', 'lightning': 'grounds' }, 'sand': { 'fire': 'smothers', 'ice': 'melts', 'lightning': 'vitrifies', 'sponge': 'absorbs', 'smoke': 'mixes with' }, 'oil': { 'sponge': 'saturates', 'gun': 'lubricates', 'sand': 'coats', 'tree': 'poisons', 'paper': 'stains' } }; // 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 battleResultText = null; // Global battle result text 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 names for all possible combinations var comboNames = { 'air+fire': 'Blazing Wind', 'air+gas': 'Toxic Cloud', 'air+gun': 'Wind Shot', 'air+ice': 'Frozen Gale', 'air+lightning': 'Thunder Storm', 'air+metal': 'Steel Breeze', 'air+oil': 'Fuel Vapor', 'air+paper': 'Paper Plane', 'air+rock': 'Flying Stone', 'air+sand': 'Sand Storm', 'air+scissors': 'Wind Blade', 'air+smoke': 'Smog Cloud', 'air+sponge': 'Airy Cushion', 'air+tree': 'Rustling Leaves', 'air+water': 'Mist', 'fire+gas': 'Explosive Blast', 'fire+gun': 'Flaming Shot', 'fire+ice': 'Steam Burst', 'fire+lightning': 'Plasma Storm', 'fire+metal': 'Molten Steel', 'fire+oil': 'Oil Fire', 'fire+paper': 'Burning Page', 'fire+rock': 'Lava Rock', 'fire+sand': 'Glass Forge', 'fire+scissors': 'Heated Blade', 'fire+smoke': 'Inferno Smoke', 'fire+sponge': 'Burning Sponge', 'fire+tree': 'Forest Fire', 'fire+water': 'Steam Power', 'gas+gun': 'Gas Shot', 'gas+ice': 'Frozen Gas', 'gas+lightning': 'Electric Gas', 'gas+metal': 'Metal Corrosion', 'gas+oil': 'Fuel Mix', 'gas+paper': 'Gas Wrapper', 'gas+rock': 'Gas Bubble', 'gas+sand': 'Gas Pocket', 'gas+scissors': 'Gas Cutter', 'gas+smoke': 'Dense Fog', 'gas+sponge': 'Gas Absorber', 'gas+tree': 'Tree Poison', 'gas+water': 'Carbonation', 'gun+ice': 'Ice Bullet', 'gun+lightning': 'Electric Gun', 'gun+metal': 'Steel Shot', 'gun+oil': 'Oiled Gun', 'gun+paper': 'Paper Target', 'gun+rock': 'Rock Bullet', 'gun+sand': 'Sand Blast', 'gun+scissors': 'Sharp Shooter', 'gun+smoke': 'Smoke Screen', 'gun+sponge': 'Soft Target', 'gun+tree': 'Wood Shot', 'gun+water': 'Water Gun', 'ice+lightning': 'Frozen Lightning', 'ice+metal': 'Frozen Steel', 'ice+oil': 'Frozen Oil', 'ice+paper': 'Ice Sheet', 'ice+rock': 'Frozen Rock', 'ice+sand': 'Frozen Sand', 'ice+scissors': 'Ice Blade', 'ice+smoke': 'Frozen Smoke', 'ice+sponge': 'Ice Block', 'ice+tree': 'Frozen Tree', 'ice+water': 'Frozen Flood', 'lightning+metal': 'Electric Conductor', 'lightning+oil': 'Electric Oil', 'lightning+paper': 'Electric Paper', 'lightning+rock': 'Thunder Stone', 'lightning+sand': 'Lightning Glass', 'lightning+scissors': 'Electric Blade', 'lightning+smoke': 'Electric Smoke', 'lightning+sponge': 'Shock Absorber', 'lightning+tree': 'Lightning Tree', 'lightning+water': 'Electrified Storm', 'metal+oil': 'Oiled Metal', 'metal+paper': 'Metal Wrapper', 'metal+rock': 'Crushing Force', 'metal+sand': 'Metal Sand', 'metal+scissors': 'Steel Scissors', 'metal+smoke': 'Metal Smoke', 'metal+sponge': 'Steel Wool', 'metal+tree': 'Metal Tree', 'metal+water': 'Rust Formation', 'oil+paper': 'Oil Stain', 'oil+rock': 'Oil Rock', 'oil+sand': 'Oil Sand', 'oil+scissors': 'Oiled Blade', 'oil+smoke': 'Oil Smoke', 'oil+sponge': 'Oil Absorber', 'oil+tree': 'Oil Tree', 'oil+water': 'Oil Spill', 'paper+rock': 'Rock Wrapper', 'paper+sand': 'Sand Paper', 'paper+scissors': 'Paper Cut', 'paper+smoke': 'Smoke Paper', 'paper+sponge': 'Paper Towel', 'paper+tree': 'Paper Wood', 'paper+water': 'Wet Paper', 'rock+sand': 'Sand Stone', 'rock+scissors': 'Rock Crusher', 'rock+smoke': 'Smoky Rock', 'rock+sponge': 'Rock Sponge', 'rock+tree': 'Rock Garden', 'rock+water': 'Rock Pool', 'sand+scissors': 'Sand Blade', 'sand+smoke': 'Dust Cloud', 'sand+sponge': 'Sand Filter', 'sand+tree': 'Desert Tree', 'sand+water': 'Mud', 'scissors+smoke': 'Smoky Blade', 'scissors+sponge': 'Soft Cut', 'scissors+tree': 'Tree Cutter', 'scissors+water': 'Wet Scissors', 'smoke+sponge': 'Smoke Filter', 'smoke+tree': 'Smoky Tree', 'smoke+water': 'Steam Cloud', 'sponge+tree': 'Tree Sponge', 'sponge+water': 'Water Sponge', 'tree+water': 'Living Tree' }; // Combo system definitions var comboEffects = { // Critical failure combos - elements that defeat each other 'water+fire': { name: 'Steam Explosion', defeatsExtra: [], multiplier: 0 }, 'fire+water': { name: 'Steam Explosion', defeatsExtra: [], multiplier: 0 }, 'rock+paper': { name: 'Torn Rock', defeatsExtra: [], multiplier: 0 }, 'paper+rock': { name: 'Torn Rock', defeatsExtra: [], multiplier: 0 }, 'scissors+paper': { name: 'Dulled Scissors', defeatsExtra: [], multiplier: 0 }, 'paper+scissors': { name: 'Dulled Scissors', defeatsExtra: [], multiplier: 0 }, 'rock+scissors': { name: 'Broken Blades', defeatsExtra: [], multiplier: 0 }, 'scissors+rock': { name: 'Broken Blades', defeatsExtra: [], multiplier: 0 }, 'water+rock': { name: 'Eroded Stone', defeatsExtra: [], multiplier: 0 }, 'rock+water': { name: 'Eroded Stone', defeatsExtra: [], multiplier: 0 }, 'fire+rock': { name: 'Cracked Stone', defeatsExtra: [], multiplier: 0 }, 'rock+fire': { name: 'Cracked Stone', defeatsExtra: [], multiplier: 0 }, 'fire+paper': { name: 'Burnt Paper', defeatsExtra: [], multiplier: 0 }, 'paper+fire': { name: 'Burnt Paper', defeatsExtra: [], multiplier: 0 }, 'fire+scissors': { name: 'Molten Scissors', defeatsExtra: [], multiplier: 0 }, 'scissors+fire': { name: 'Molten Scissors', defeatsExtra: [], multiplier: 0 }, 'fire+tree': { name: 'Forest Fire', defeatsExtra: [], multiplier: 0 }, 'tree+fire': { name: 'Forest Fire', defeatsExtra: [], multiplier: 0 }, 'fire+gas': { name: 'Gas Explosion', defeatsExtra: [], multiplier: 0 }, 'gas+fire': { name: 'Gas Explosion', defeatsExtra: [], multiplier: 0 }, 'fire+ice': { name: 'Steam Burst', defeatsExtra: [], multiplier: 0 }, 'ice+fire': { name: 'Steam Burst', defeatsExtra: [], multiplier: 0 }, // Working 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: 'Blazing Wind', 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 }, 'lightning+metal': { name: 'Electric Conductor', defeatsExtra: ['water', 'ice', 'gun'], multiplier: 1.7 }, 'air+metal': { name: 'Steel Storm', defeatsExtra: ['rock', 'paper', 'tree'], multiplier: 1.6 }, 'ice+metal': { name: 'Frozen Steel', defeatsExtra: ['fire', 'lightning', 'air'], multiplier: 1.5 }, 'gas+oil': { name: 'Fuel Mixture', defeatsExtra: ['water', 'sponge', 'ice'], multiplier: 2.2 }, 'tree+water': { name: 'Living Forest', defeatsExtra: ['fire', 'sand', 'oil'], multiplier: 1.4 }, 'smoke+gas': { name: 'Toxic Cloud', defeatsExtra: ['air', 'tree', 'sponge'], multiplier: 1.9 } }; // 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(); // Play music based on weather type if (currentWeather === 'windy') { LK.playMusic('air'); } else if (currentWeather === 'drought') { LK.playMusic('draught'); } else if (currentWeather === 'rainy') { LK.playMusic('rain'); } else if (currentWeather === 'storm') { LK.playMusic('storm'); } } // 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) && !button.isDisabled) { // Replace elementButton with boostedElementButton for visual enhancement var background = button.children[0]; // The button background is the first child if (background) { // Remove old background button.removeChild(background); // Add boosted background with weather-specific variant var boostedAssetName = 'boostedElementButton'; // default if (currentWeather === 'storm') { boostedAssetName = 'boostElementButtonStormy'; } else if (currentWeather === 'rainy') { boostedAssetName = 'boostedElementButtonRain'; } else if (currentWeather === 'drought') { boostedAssetName = 'boostedElementButtonDraught'; } else if (currentWeather === 'windy') { boostedAssetName = 'boostedElementButtonWind'; } var boostedBackground = button.attachAsset(boostedAssetName, { 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) { // Check if it's currently boosted and needs to be replaced 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 getComboName(combo) { if (combo.length !== 2) { return null; } var key = getComboKey(combo); return comboNames[key] || null; } 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(playerCombo[0].toUpperCase()); 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); } else if (playerCombo.length === 2) { var effect = getComboEffect(playerCombo); var comboName = getComboName(playerCombo); if (effect) { comboDisplay.setText(effect.name); comboDisplay.tint = 0x00FF00; // Green for special combo } else if (comboName) { comboDisplay.setText(comboName); comboDisplay.tint = 0xFFD700; // Gold for normal combo } else { comboDisplay.setText('Unknown 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 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(aiCombo[0].toUpperCase()); 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); var comboName = getComboName(aiCombo); if (effect) { aiComboDisplay.setText(effect.name); aiComboDisplay.tint = 0x00FF00; // Green for special combo } else if (comboName) { aiComboDisplay.setText(comboName); aiComboDisplay.tint = 0xFFD700; // Gold for normal combo } else { aiComboDisplay.setText('Unknown 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; // Player health bar at bottom var playerHealthBarBg = LK.getAsset('healthBarBg', { anchorX: 0, anchorY: 1, scaleX: 14, scaleY: 0.5 }); playerHealthBarBg.tint = 0x333333; LK.gui.bottom.addChild(playerHealthBarBg); playerHealthBarBg.x = -700; playerHealthBarBg.y = -60; var playerHealthBar = LK.getAsset('healthBar', { anchorX: 0, anchorY: 1, scaleX: 14, scaleY: 0.5 }); playerHealthBar.tint = 0x00FF00; LK.gui.bottom.addChild(playerHealthBar); playerHealthBar.x = -700; playerHealthBar.y = -60; var playerHealthText = new Text2('PLAYER: 100/100', { size: 28, fill: 0xFFFFFF, font: "Trebuchet MS, Arial, sans-serif", stroke: 0x000000, strokeThickness: 3 }); playerHealthText.anchor.set(0.5, 0.5); LK.gui.bottom.addChild(playerHealthText); playerHealthText.x = 0; playerHealthText.y = -90; // AI health bar at bottom var aiHealthBarBg = LK.getAsset('healthBarBg', { anchorX: 0, anchorY: 1, scaleX: 14, scaleY: 0.5 }); aiHealthBarBg.tint = 0x333333; LK.gui.bottom.addChild(aiHealthBarBg); aiHealthBarBg.x = -700; aiHealthBarBg.y = -10; var aiHealthBar = LK.getAsset('healthBar', { anchorX: 0, anchorY: 1, scaleX: 14, scaleY: 0.5 }); aiHealthBar.tint = 0xFF0000; LK.gui.bottom.addChild(aiHealthBar); aiHealthBar.x = -700; aiHealthBar.y = -10; var aiHealthText = new Text2('AI: 100/100', { size: 28, fill: 0xFFFFFF, font: "Trebuchet MS, Arial, sans-serif", stroke: 0x000000, strokeThickness: 3 }); aiHealthText.anchor.set(0.5, 0.5); LK.gui.bottom.addChild(aiHealthText); aiHealthText.x = 0; aiHealthText.y = -35; 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 } // Play sound for specific elements if (elementType === 'rock' || elementType === 'paper' || elementType === 'scissors' || elementType === 'fire' || elementType === 'metal' || elementType === 'water' || elementType === 'air' || elementType === 'lightning' || elementType === 'tree' || elementType === 'gun' || elementType === 'sponge' || elementType === 'smoke' || elementType === 'gas' || elementType === 'ice' || elementType === 'sand' || elementType === 'oil') { LK.getSound(elementType).play(); } if (elementType === 'air') LK.getSound('airy').play(); // 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 // Play sound for specific elements when AI selects them if (currentTopElement === 'rock' || currentTopElement === 'paper' || currentTopElement === 'scissors' || currentTopElement === 'fire' || currentTopElement === 'metal' || currentTopElement === 'water' || currentTopElement === 'air' || currentTopElement === 'lightning' || currentTopElement === 'tree' || currentTopElement === 'gun' || currentTopElement === 'sponge' || currentTopElement === 'smoke' || currentTopElement === 'gas' || currentTopElement === 'ice' || currentTopElement === 'sand' || currentTopElement === 'oil') { LK.getSound(currentTopElement).play(); } 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 combo lines during battle if (game.playerComboLines) { for (var i = 0; i < game.playerComboLines.length; i++) { tween(game.playerComboLines[i], { alpha: 0 }, { duration: 300 }); } } if (game.aiComboLines) { for (var i = 0; i < game.aiComboLines.length; i++) { tween(game.aiComboLines[i], { 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 }); // Create VS battle text with combo/element names var playerDisplayText = ''; var aiDisplayText = ''; // Get player display name if (playerCombo.length === 2) { var playerComboName = getComboName(playerCombo); var playerComboEffect = getComboEffect(playerCombo); if (playerComboEffect) { playerDisplayText = playerComboEffect.name; } else if (playerComboName) { playerDisplayText = playerComboName; } else { playerDisplayText = playerCombo.join(' + ').toUpperCase(); } } else if (playerElement) { playerDisplayText = playerElement.toUpperCase(); } else { playerDisplayText = 'PLAYER'; } // Get AI display name if (aiCombo.length === 2) { var aiComboName = getComboName(aiCombo); var aiComboEffect = getComboEffect(aiCombo); if (aiComboEffect) { aiDisplayText = aiComboEffect.name; } else if (aiComboName) { aiDisplayText = aiComboName; } else { aiDisplayText = aiCombo.join(' + ').toUpperCase(); } } else if (aiElement) { aiDisplayText = aiElement.toUpperCase(); } else { aiDisplayText = 'AI'; } // Add battle instruction text vsText = new Text2(playerDisplayText + '\nVS\n' + aiDisplayText, { size: 80, fill: 0xFF6B35, font: "Trebuchet MS, Arial, sans-serif", stroke: 0xffffff, strokeThickness: 8, align: 'center' }); 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) battleResultText = new Text2('', { size: 60, fill: 0xFFFFFF, font: "Trebuchet MS, Arial, sans-serif", stroke: 0xffffff, strokeThickness: 6, align: "center" }); battleResultText.anchor.set(0.5, 0.5); battleResultText.x = 1024; battleResultText.y = 1500; battleResultText.alpha = 0; game.addChild(battleResultText); tween(vsText, { alpha: 1, scaleX: 1.2, scaleY: 1.2 }, { duration: 3000, 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; // Check for critical failures (opposing elements that defeat each other) var playerCriticalFailure = false; var aiCriticalFailure = false; if (playerCombo.length === 2) { // Check if player combo elements defeat each other (critical failure) if (defeats[playerCombo[0]] && defeats[playerCombo[0]].indexOf(playerCombo[1]) !== -1 || defeats[playerCombo[1]] && defeats[playerCombo[1]].indexOf(playerCombo[0]) !== -1) { playerCriticalFailure = true; } // Also check if combo effect has multiplier 0 (registered critical failure) if (playerComboEffect && playerComboEffect.multiplier === 0) { playerCriticalFailure = true; } } if (aiCombo.length === 2) { // Check if AI combo elements defeat each other (critical failure) if (defeats[aiCombo[0]] && defeats[aiCombo[0]].indexOf(aiCombo[1]) !== -1 || defeats[aiCombo[1]] && defeats[aiCombo[1]].indexOf(aiCombo[0]) !== -1) { aiCriticalFailure = true; } // Also check if combo effect has multiplier 0 (registered critical failure) if (aiComboEffect && aiComboEffect.multiplier === 0) { aiCriticalFailure = true; } } // Critical failures override all other battle logic if (playerCriticalFailure && !aiCriticalFailure) { return 'ai'; // Player loses due to critical failure } else if (aiCriticalFailure && !playerCriticalFailure) { return 'player'; // AI loses due to critical failure } else if (playerCriticalFailure && aiCriticalFailure) { return 'tie'; // Both have critical failures } // 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'; } } // Combo win condition: A combo wins if either of its elements defeats both of the opponent's elements. var playerComboWinsAll = false; if (playerBattleElements.length === 2 && aiBattleElements.length === 2) { if (defeats[playerBattleElements[0]] && defeats[playerBattleElements[0]].indexOf(aiBattleElements[0]) !== -1 && defeats[playerBattleElements[0]].indexOf(aiBattleElements[1]) !== -1) { playerComboWinsAll = true; } else if (defeats[playerBattleElements[1]] && defeats[playerBattleElements[1]].indexOf(aiBattleElements[0]) !== -1 && defeats[playerBattleElements[1]].indexOf(aiBattleElements[1]) !== -1) { playerComboWinsAll = true; } } var aiComboWinsAll = false; if (playerBattleElements.length === 2 && aiBattleElements.length === 2) { if (defeats[aiBattleElements[0]] && defeats[aiBattleElements[0]].indexOf(playerBattleElements[0]) !== -1 && defeats[aiBattleElements[0]].indexOf(playerBattleElements[1]) !== -1) { aiComboWinsAll = true; } else if (defeats[aiBattleElements[1]] && defeats[aiBattleElements[1]].indexOf(playerBattleElements[0]) !== -1 && defeats[aiBattleElements[1]].indexOf(playerBattleElements[1]) !== -1) { aiComboWinsAll = 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 (playerComboWinsAll && !aiComboWinsAll) { return 'player'; } else if (aiComboWinsAll && !playerComboWinsAll) { return 'ai'; } else if (playerWins && !aiWins) { return 'player'; } else if (aiWins && !playerWins) { 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 && playerComboEffect.multiplier > 1; var playerIsFailure = false; var aiIsCritical = aiCombo.length === 2 && aiComboEffect !== null && aiComboEffect.multiplier > 1; var aiIsFailure = false; // Check for critical failures (opposing elements that defeat each other) if (playerCombo.length === 2) { // Check if player combo elements defeat each other (critical failure) if (defeats[playerCombo[0]] && defeats[playerCombo[0]].indexOf(playerCombo[1]) !== -1 || defeats[playerCombo[1]] && defeats[playerCombo[1]].indexOf(playerCombo[0]) !== -1) { playerIsFailure = true; } // Also check if combo effect has multiplier 0 (registered critical failure) if (playerComboEffect && playerComboEffect.multiplier === 0) { playerIsFailure = true; } } if (aiCombo.length === 2) { // Check if AI combo elements defeat each other (critical failure) if (defeats[aiCombo[0]] && defeats[aiCombo[0]].indexOf(aiCombo[1]) !== -1 || defeats[aiCombo[1]] && defeats[aiCombo[1]].indexOf(aiCombo[0]) !== -1) { aiIsFailure = true; } // Also check if combo effect has multiplier 0 (registered critical failure) if (aiComboEffect && aiComboEffect.multiplier === 0) { aiIsFailure = true; } } var baseDamage = 10; var playerDamage = baseDamage; var aiDamage = baseDamage; // Apply critical effects if (playerIsCritical) { // Critical success - double damage to opponent } else if (playerIsFailure) { // Critical failure - damage to self (applied in result section) } if (aiIsCritical) { // Critical success - double damage to opponent } else if (aiIsFailure) { // Critical failure - damage to self (applied in result section) } if (result === 'player') { LK.getSound('win').play(); playerBattleElement.playWinAnimation(); aiBattleElement.playLoseAnimation(); // Player wins - damage to AI var damage = playerIsCritical ? baseDamage * 2 : baseDamage; aiLife -= damage; if (aiLife < 0) { aiLife = 0; } // Create result text with combo names var playerDesc = ''; if (playerElement) { playerDesc = playerElement.toUpperCase(); } else if (playerCombo.length === 2) { var playerComboName = getComboName(playerCombo); playerDesc = playerComboName || playerCombo.join(' + ').toUpperCase(); } var aiDesc = ''; if (aiElement) { aiDesc = aiElement.toUpperCase(); } else if (aiCombo.length === 2) { var aiComboName = getComboName(aiCombo); aiDesc = aiComboName || aiCombo.join(' + ').toUpperCase(); } 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!'; } // Add explanation for why player won var explanation = ''; if (playerCombo.length === 2 && aiCombo.length === 2) { // Combo vs combo explanation var playerComboEffect = getComboEffect(playerCombo); if (playerComboEffect && playerComboEffect.defeatsExtra.length > 0) { explanation = '\n' + playerComboEffect.name + ' combo defeats extra elements!'; } else { explanation = '\nYour combo elements dominate their elements!'; } } else if (playerCombo.length === 2 && aiElement) { // Combo vs single explanation explanation = '\nYour combo overwhelms their single element!'; } else if (playerElement && aiCombo.length === 2) { // Single vs combo explanation explanation = '\nYour element exploits their combo weakness!'; } else if (playerElement && aiElement) { // Single vs single explanation var actionDesc = getActionKeyword(playerElement, aiElement); explanation = '\n' + playerElement.toUpperCase() + ' ' + actionDesc + ' ' + aiElement.toUpperCase() + ' by nature!'; } // Check for weather bonus explanation var playerHasBonus = false; for (var i = 0; i < (playerElement ? [playerElement] : playerCombo).length; i++) { if (hasWeatherBonus((playerElement ? [playerElement] : playerCombo)[i])) { playerHasBonus = true; break; } } if (playerHasBonus) { explanation += '\nWeather boost gives you the advantage!'; } resultText += explanation; battleResultText.setText(resultText); battleResultText.tint = 0x00ff00; battleResultText.alpha = 1; tween(battleResultText, { alpha: 1, scaleX: 1.2, scaleY: 1.2 }, { duration: 500 }); // Shake/blink animation for SUCCESS // Check for AI death if (playerLife > 0 && 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 ? baseDamage * 2 : baseDamage; playerLife -= damage; if (playerLife < 0) { playerLife = 0; } var aiDesc = ''; if (aiElement) { aiDesc = aiElement.toUpperCase(); } else if (aiCombo.length === 2) { var aiComboName = getComboName(aiCombo); aiDesc = aiComboName || aiCombo.join(' + ').toUpperCase(); } var playerDesc = ''; if (playerElement) { playerDesc = playerElement.toUpperCase(); } else if (playerCombo.length === 2) { var playerComboName = getComboName(playerCombo); playerDesc = playerComboName || playerCombo.join(' + ').toUpperCase(); } 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!'; } // Add explanation for why AI won var explanation = ''; if (aiCombo.length === 2 && playerCombo.length === 2) { // Combo vs combo explanation var aiComboEffect = getComboEffect(aiCombo); if (aiComboEffect && aiComboEffect.defeatsExtra.length > 0) { explanation = '\n' + aiComboEffect.name + ' combo defeats extra elements!'; } else { explanation = '\nAI combo elements dominate your elements!'; } } else if (aiCombo.length === 2 && playerElement) { // Combo vs single explanation explanation = '\nAI combo overwhelms your single element!'; } else if (aiElement && playerCombo.length === 2) { // Single vs combo explanation explanation = '\nAI element exploits your combo weakness!'; } else if (aiElement && playerElement) { // Single vs single explanation var actionDesc = getActionKeyword(aiElement, playerElement); explanation = '\n' + aiElement.toUpperCase() + ' ' + actionDesc + ' ' + playerElement.toUpperCase() + ' by nature!'; } // Check for weather bonus explanation var aiHasBonus = false; for (var i = 0; i < (aiElement ? [aiElement] : aiCombo).length; i++) { if (hasWeatherBonus((aiElement ? [aiElement] : aiCombo)[i])) { aiHasBonus = true; break; } } if (aiHasBonus) { explanation += '\nWeather boost gives AI the advantage!'; } resultText += explanation; battleResultText.setText(resultText); battleResultText.tint = 0xff0000; battleResultText.alpha = 1; tween(battleResultText, { alpha: 1, scaleX: 1.2, scaleY: 1.2 }, { duration: 500 }); // Shake/blink animation for FAILURE // Check for player death if (playerLife <= 0 && aiLife > 0) { LK.showGameOver(); return; } } else { // Handle critical failures in ties if (playerIsFailure && !aiIsFailure) { // Player critical failure - damage to player playerLife -= baseDamage; if (playerLife < 0) { playerLife = 0; } var explanation = '\nOpposing elements in your combo cancel each other out!'; if (playerCombo.length === 2) { var elem1 = playerCombo[0].toUpperCase(); var elem2 = playerCombo[1].toUpperCase(); explanation = '\n' + elem1 + ' and ' + elem2 + ' work against each other!'; } battleResultText.setText('TIE!\nCRITICAL FAILURE! -' + baseDamage + ' Life' + explanation); battleResultText.tint = 0xff0000; battleResultText.alpha = 1; tween(battleResultText, { alpha: 1, scaleX: 1.2, scaleY: 1.2 }, { duration: 500 }); // Shake/blink animation for CRITICAL FAILURE if (playerLife <= 0 && aiLife > 0) { LK.showGameOver(); return; } } else if (aiIsFailure && !playerIsFailure) { // AI critical failure - damage to AI aiLife -= baseDamage; if (aiLife < 0) { aiLife = 0; } var explanation = '\nOpposing elements in AI combo cancel each other out!'; if (aiCombo.length === 2) { var elem1 = aiCombo[0].toUpperCase(); var elem2 = aiCombo[1].toUpperCase(); explanation = '\n' + elem1 + ' and ' + elem2 + ' work against each other!'; } battleResultText.setText('TIE!\nAI CRITICAL FAILURE! -' + baseDamage + ' AI Life' + explanation); battleResultText.tint = 0x00ff00; battleResultText.alpha = 1; tween(battleResultText, { alpha: 1, scaleX: 1.2, scaleY: 1.2 }, { duration: 500 }); // Shake/blink animation for CRITICAL FAILURE if (aiLife <= 0) { LK.showYouWin(); return; } } else if (playerIsFailure && aiIsFailure) { // Both critical failures playerLife -= baseDamage; aiLife -= baseDamage; if (playerLife < 0) { playerLife = 0; } if (aiLife < 0) { aiLife = 0; } var explanation = '\nBoth combos have opposing elements that cancel out!'; battleResultText.setText('TIE!\nBOTH CRITICAL FAILURES!' + explanation); battleResultText.tint = 0xffff00; battleResultText.alpha = 1; tween(battleResultText, { alpha: 1, scaleX: 1.2, scaleY: 1.2 }, { duration: 500 }); // Shake/blink animation for BOTH CRITICAL FAILURES if (playerLife <= 0 && aiLife <= 0) { LK.showGameOver(); // Player dies first in simultaneous death return; } else if (playerLife <= 0 && aiLife > 0) { LK.showGameOver(); return; } else if (aiLife <= 0 && playerLife > 0) { LK.showYouWin(); return; } } else { var explanation = ''; if (playerElement && aiElement) { explanation = '\nNeither element has advantage over the other!'; } else if (playerCombo.length === 2 && aiCombo.length === 2) { explanation = '\nBoth combos are equally matched!'; } else { explanation = '\nForces are perfectly balanced!'; } // Check for weather effects on ties var playerHasBonus = false; var aiHasBonus = false; for (var i = 0; i < (playerElement ? [playerElement] : playerCombo).length; i++) { if (hasWeatherBonus((playerElement ? [playerElement] : playerCombo)[i])) { playerHasBonus = true; break; } } for (var i = 0; i < (aiElement ? [aiElement] : aiCombo).length; i++) { if (hasWeatherBonus((aiElement ? [aiElement] : aiCombo)[i])) { aiHasBonus = true; break; } } if (playerHasBonus && aiHasBonus) { explanation += '\nBoth sides have weather advantage!'; } battleResultText.setText('TIE!' + explanation); battleResultText.tint = 0xffff00; battleResultText.alpha = 1; tween(battleResultText, { alpha: 1, scaleX: 1.2, scaleY: 1.2 }, { duration: 500 }); // Shake/blink animation for TIE } } // Update health bars var playerHealthPercent = playerLife / 100; var aiHealthPercent = aiLife / 100; playerHealthBar.scaleX = 14 * playerHealthPercent; aiHealthBar.scaleX = 14 * aiHealthPercent; playerHealthText.setText('PLAYER: ' + playerLife + '/100'); aiHealthText.setText('AI: ' + aiLife + '/100'); // 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(); } } // Check if all elements are used up var allElementsUsed = true; for (var i = 0; i < elementButtons.length; i++) { if (!elementButtons[i].isDisabled) { window.alert("ALL"); allElementsUsed = false; break; } } // Check if all elements are used up var allElementsUsed = true; for (var i = 0; i < elementButtons.length; i++) { if (!elementButtons[i].isDisabled) { allElementsUsed = false; break; } } // Game over if player health is zero and AI health is greater than zero if (playerLife <= 0 && aiLife > 0) { LK.showGameOver(); return; } // Return to selection after delay LK.setTimeout(function () { resetForNextRound(); }, 5000); } // Create bezier lines between combo elements function createComboLines(combo, isPlayer) { if (combo.length !== 2) { return; } // Find element buttons for the combo elements var element1Button = null; var element2Button = null; for (var i = 0; i < elementButtons.length; i++) { if (elementButtons[i].elementType === combo[0]) { element1Button = elementButtons[i]; } if (elementButtons[i].elementType === combo[1]) { element2Button = elementButtons[i]; } } if (!element1Button || !element2Button) { return; } // Calculate positions relative to wheel center var startX = element1Button.x; var startY = element1Button.y; var endX = element2Button.x; var endY = element2Button.y; // Control point at wheel center for curved line var controlX = 0; var controlY = 0; // Create container for the combo line var lineContainer = new Container(); wheelContainer.addChild(lineContainer); // Number of segments for the bezier curve var segments = 40; var lineColor = isPlayer ? 0x00FF00 : 0xFF0000; // Green for player, red for AI // 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 }); lineContainer.addChild(lineSegment); // Position and rotate the segment lineSegment.x = x1; lineSegment.y = y1; lineSegment.rotation = angle; lineSegment.width = distance; lineSegment.height = 6; // Line thickness lineSegment.tint = lineColor; lineSegment.alpha = 0.7; // Semi-transparent } // Animate line appearance lineContainer.alpha = 0; tween(lineContainer, { alpha: 1 }, { duration: 500 }); // Store reference for cleanup if (isPlayer) { if (!game.playerComboLines) game.playerComboLines = []; game.playerComboLines.push(lineContainer); } else { if (!game.aiComboLines) game.aiComboLines = []; game.aiComboLines.push(lineContainer); } } // 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; // Clean up combo lines if (game.playerComboLines) { for (var i = 0; i < game.playerComboLines.length; i++) { game.playerComboLines[i].destroy(); } game.playerComboLines = []; } if (game.aiComboLines) { for (var i = 0; i < game.aiComboLines.length; i++) { game.aiComboLines[i].destroy(); } game.aiComboLines = []; } 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) { tween.stop(battleResultText); // Stop any ongoing tween animation 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 }); } // Create combo lines for completed combos after battle if (playerCombo.length === 2) { createComboLines(playerCombo, true); } if (aiCombo.length === 2) { createComboLines(aiCombo, false); } // Show combo lines again after battle if (game.playerComboLines) { for (var i = 0; i < game.playerComboLines.length; i++) { tween(game.playerComboLines[i], { alpha: 1 }, { duration: 300 }); } } if (game.aiComboLines) { for (var i = 0; i < game.aiComboLines.length; i++) { tween(game.aiComboLines[i], { 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
@@ -887,10 +887,8 @@
} else {
comboDisplay.setText('Unknown Combo');
comboDisplay.tint = 0xFFD700; // Gold for normal combo
}
- // Create bezier lines between combo elements
- createComboLines(playerCombo, true);
var icon1 = LK.getAsset(playerCombo[0], {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.9,
@@ -952,10 +950,8 @@
} else {
aiComboDisplay.setText('Unknown Combo');
aiComboDisplay.tint = 0xFFD700; // Gold for normal combo
}
- // Create bezier lines between combo elements
- createComboLines(aiCombo, false);
var icon1 = LK.getAsset(aiCombo[0], {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.9,
@@ -2595,8 +2591,15 @@
}, {
duration: 300
});
}
+ // Create combo lines for completed combos after battle
+ if (playerCombo.length === 2) {
+ createComboLines(playerCombo, true);
+ }
+ if (aiCombo.length === 2) {
+ createComboLines(aiCombo, false);
+ }
// Show combo lines again after battle
if (game.playerComboLines) {
for (var i = 0; i < game.playerComboLines.length; i++) {
tween(game.playerComboLines[i], {
@@ -2614,15 +2617,8 @@
duration: 300
});
}
}
- // Recreate combo lines for current round if they exist
- if (playerCombo.length === 2) {
- createComboLines(playerCombo, true);
- }
- if (aiCombo.length === 2) {
- createComboLines(aiCombo, false);
- }
// 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;
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