User prompt
Make this the case for this skill: Overclock Core: Increases attack speed and energy regeneration—+2.5 % & +2.0 %, +2.0 % & +1.6 %, +1.5 % & +1.2 %, +1.0 % & +0.8 %, then +0.5 % & +0.4 % for a total of +7.5 % attack speed and +6.0 % energy regen at rank 5. Make sure the description updates to reflect both stats. For example: "Increases attack speed by 2.5% and energy regeneration by 2.0%." Then: "Increases attack speed by 2.0% and energy regeneration by 1.6% (Currently 2.5% / 2.0%)."
User prompt
Now Overclock Core: Increases attack speed and energy regeneration—+2.5 % & +2.0 %, +2.0 % & +1.6 %, +1.5 % & +1.2 %, +1.0 % & +0.8 %, then +0.5 % & +0.4 % for a total of +7.5 % attack speed and +6.0 % energy regen at rank 5. Make sure the description updates to reflect both stats. For example: "Increases attack speed by 2.5% and energy regeneration by 2.0%." Then: "Increases attack speed by 2.0% and energy regeneration by 1.6% (Currently 2.5% / 2.0%)."
User prompt
Make this the case for this skill: Here is the template to follow: Reflex Accelerator: Boosts movement speed—+10 %, +8 %, +6 %, +4 %, then +2 % for a total of +30 % at rank 5. Make sure the description updates each time a skill point is spent to represent this. For example: Boosts movement speed by 10% for the first point. Then, after a skill point is placed into it and the allocation text changes to 1/5, the description changes to "Boosts movement speed by 8% (Currently 10%)". This is how Each point should increase it.
User prompt
Lets just get rid of the skill allocation numbers below each skill node since we have it dynamically in the popup description.
User prompt
After leaving the skill node popup i.e. pressing cancel button, have the skill tree popup that's currently open update or refresh by performing the back button and re-entering the skill tree popup
User prompt
Maybe you're not understanding, when that cancel button is pressed, perform the equivalent of pressing the back button on the skill tree popup and re-enter into the same skill tree popup to perform a "refresh" of that popup
User prompt
After leaving the skill node popup i.e. pressing cancel button, have the skill tree popup that's currently open update or refresh.
User prompt
Try again
User prompt
the numbers are both updating, but the number under the skill tree node is not updating until I leave the current screen by pressing the back button and then re-open it. Is there anyway to get that to work?
User prompt
Great, the numbers are both updating, but the number under the skill tree node is not updating until I leave the current screen by pressing the back button and then re-open it.
User prompt
Hmmm, I now have a number updating correctly when points are spent, inside of the skill description. This is fine, except that the numbers under each skill node do not change also. Maybe attach those numbers to eachother to both update?
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'includes')' in or related to this line: 'return child instanceof Text2 && child.text.includes('/') && child.y > skillPopup.height / 2;' Line Number: 1460
User prompt
The number beneath the skill node does not update dynamically from 0/5 to 1/5 when I spend a skill point into the skill node like it should
User prompt
Great, now when I am "spending" my skill points into the skill node of choice, I want the 0/5 number to increase each spend i.e. 1/5, 2/5, and so on. Do not allow anymore then the max number.
User prompt
Great, now for the next ranks, take out the words "Each rank" so they start with Increases.
User prompt
Great, except that I want the first description to just say "Increases critical strike chance by 5%"
User prompt
Make this the case for this skill: Data Spike: Each rank increases critical hit chance with diminishing returns—+5 %, +4 %, +3 %, +2 %, then +1 % for a total of +15 % at rank 5. Make sure the description updates each time a skill point is spent to represent this. For example: Each rank increases critical strike chance by 5% for the first point. Then, after a skill point is placed into it and the allocation text changes to 1/5, the description changes to "Each rank increases critical strike chance by 4%(Currently 5%)". This is how Each point should increase it.
User prompt
Make this the case for this skill: Data Spike: Each rank increases critical hit chance with diminishing returns—+5 %, +4 %, +3 %, +2 %, then +1 % for a total of +15 % at rank 5. Make sure the description updates each time to represent this.
User prompt
That worked! Now do it for the other 5 skill tree nodes
User prompt
I still don't see it
User prompt
The skill points allocation that is supposed to be under the nodes is still not visible, can we test a fix for this just on the first node under circuit of Ascension, then I will see if it works.
User prompt
Did you add the text for skill point allocation under each node? If so, they are not visible
User prompt
Hello, I want to create a text just below each node that shows the amount each skill has put into it and how much the "max" points in it are. I will tell you eventually how much each one gets, but for now make each one 0/5 as placeholders.
User prompt
For each skill tree Shift nodes, skill name, description, and cancel and spend buttons down a little. Leave the title at the top.
User prompt
The Circuit of Ascension background, icons, and text has been shifted for some reason. It's not like the rest like it should be
/**** * Classes ****/ // AimingJoystick class for aiming separately from movement var AimingJoystick = Container.expand(function () { var self = Container.call(this); var joystickBackground = self.attachAsset('joystickBackground', { anchorX: 0.5, anchorY: 0.5 }); var joystickHandle = self.attachAsset('joystickHandle', { anchorX: 0.5, anchorY: 0.5 }); self.x = 2048 - joystickBackground.width / 2 - 100; self.y = 2732 - joystickBackground.height / 2 - 100; var maxRadius = 100; var isDragging = false; self.down = function (x, y, obj) { isDragging = true; }; self.move = function (x, y, obj) { if (isDragging && !isPopupActive) { var localPos = self.toLocal(obj.global); var dx = localPos.x; var dy = localPos.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > maxRadius) { var angle = Math.atan2(dy, dx); dx = maxRadius * Math.cos(angle); dy = maxRadius * Math.sin(angle); } joystickHandle.x = dx; joystickHandle.y = dy; } }; self.up = function (x, y, obj) { isDragging = false; joystickHandle.x = 0; joystickHandle.y = 0; }; self.getDirection = function () { var magnitude = Math.sqrt(joystickHandle.x * joystickHandle.x + joystickHandle.y * joystickHandle.y); if (magnitude > 0) { return { x: joystickHandle.x / magnitude, y: joystickHandle.y / magnitude }; } return { x: 0, y: 0 }; }; self.getRotation = function () { if (joystickHandle.x === 0 && joystickHandle.y === 0) { return null; // No direction provided } return Math.atan2(joystickHandle.y, joystickHandle.x); }; self.hasInput = function () { return joystickHandle.x !== 0 || joystickHandle.y !== 0; }; return self; }); // Arrow class representing the arrows fired by the hero var Arrow = Container.expand(function () { var self = Container.call(this); self.attachAsset('arrow', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 15; self.damage = 5; self.update = function () { self.x += Math.cos(self.rotation) * self.speed; self.y += Math.sin(self.rotation) * self.speed; if (self.x < 0 || self.x > 2048 || self.y < 0 || self.y > 2732) { self.destroy(); } }; }); // BackButton class representing the back button functionality var BackButton = Container.expand(function () { var self = Container.call(this); self.attachAsset('backButton', { anchorX: 0.5, anchorY: 0.5, scaleX: 2, scaleY: 2 }); self.x = 150; self.y = 350; self.down = function () { menuContainer.removeChild(self.parent); menuContainer.addChild(skillTreePopup); }; return self; }); // Enemy class representing the enemy character var Enemy = Container.expand(function () { var self = Container.call(this); var enemyGraphics = self.attachAsset('enemy_run1', { anchorX: 0.5, anchorY: 0.5 }); var frames = [LK.getAsset('enemy_run1', { anchorX: 0.5, anchorY: 0.5 }), LK.getAsset('enemy_run2', { anchorX: 0.5, anchorY: 0.5 }), LK.getAsset('enemy_run3', { anchorX: 0.5, anchorY: 0.5 }), LK.getAsset('enemy_run4', { anchorX: 0.5, anchorY: 0.5 })]; self.speed = 2 + Math.random() * 0.5; self.damageCooldown = 0; var currentFrame = 0; var frameDelay = 30; var frameCounter = 0; self.update = function () { frameCounter++; if (frameCounter >= frameDelay) { frameCounter = 0; self.removeChild(enemyGraphics); currentFrame = (currentFrame + 1) % frames.length; enemyGraphics = self.addChild(frames[currentFrame]); } var offsetX = (Math.random() - 0.5) * 20; var offsetY = (Math.random() - 0.5) * 20; var dx = hero.x + offsetX - self.x; var dy = hero.y + offsetY - self.y; var distance = Math.sqrt(dx * dx + dy * dy); var minDistance = 70; if (distance > minDistance) { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; self.rotation = Math.atan2(dy, dx); } else { if (self.damageCooldown <= 0) { hero.health -= 5; self.damageCooldown = 60; updateRoomDisplay(); } else { self.damageCooldown--; } self.x -= dx / distance * (minDistance - distance); self.y -= dy / distance * (minDistance - distance); } if (self.x < wallThickness) { self.x = wallThickness; } if (self.x > roomWidth - wallThickness) { self.x = roomWidth - wallThickness; } if (self.y < wallThickness) { self.y = wallThickness; } if (self.y > roomHeight - wallThickness) { self.y = roomHeight - wallThickness; } }; return self; }); // Hero class representing the player character var Hero = Container.expand(function () { var self = Container.call(this); var heroGraphics = self.attachAsset('hero', { anchorX: 0.5, anchorY: 0.5 }); self.swordGraphics = heroGraphics.addChild(LK.getAsset('sword', { anchorX: 0.5, anchorY: 0.5 })); self.swordGraphics.x = heroGraphics.width / 2 + 20; self.swordGraphics.y = 0; self.bowGraphics = self.attachAsset('bow', { anchorX: 0.5, anchorY: 0.5 }); self.bowGraphics.x = heroGraphics.width / 2; self.bowGraphics.visible = false; self.attackCooldown = 0; self.isAttacking = false; self.health = 100; self.attackDuration = 20; self.attackDurationCounter = 0; // Counter to track swing animation progress self.weaponType = 1; self.attackRange = 60; self.attackDamage = 10; self.speed = 3; // Attack speeds for different weapons self.swordAttackSpeed = 45; // Frames between sword attacks self.bowAttackSpeed = 30; // Frames between arrow shots self.joystick = null; self.aimingJoystick = null; // Properties to track facing direction separately from aiming direction self.facingDirection = 0; // Angle in radians self.update = function () { // Movement handling var direction = this.joystick ? this.joystick.getDirection() : { x: 0, y: 0 }; var nextX = this.x + direction.x * this.speed; var nextY = this.y + direction.y * this.speed; // Wall collision detection if (nextX < wallThickness && !(nextY >= entrances.left.yStart && nextY <= entrances.left.yEnd)) { nextX = wallThickness; } else if (nextX > roomWidth - wallThickness && !(nextY >= entrances.right.yStart && nextY <= entrances.right.yEnd)) { nextX = roomWidth - wallThickness; } if (nextY < wallThickness && !(nextX >= entrances.top.xStart && nextX <= entrances.top.xEnd)) { nextY = wallThickness; } else if (nextY > roomHeight - wallThickness && !(nextX >= entrances.bottom.xStart && nextX <= entrances.bottom.xEnd)) { nextY = roomHeight - wallThickness; } this.x = nextX; this.y = nextY; // Update facing direction if moving if (direction.x !== 0 || direction.y !== 0) { self.facingDirection = Math.atan2(direction.y, direction.x); // Only rotate hero graphics for movement if not aiming if (!self.aimingJoystick || !self.aimingJoystick.hasInput()) { // Use facing direction for hero rotation self.rotation = self.facingDirection; } } // If aiming joystick has input, use that direction for weapon aiming if (self.aimingJoystick && self.aimingJoystick.hasInput()) { var aimAngle = self.aimingJoystick.getRotation(); if (aimAngle !== null) { // Rotate the hero for aiming self.rotation = aimAngle; // Position weapons correctly based on aim direction if (self.weaponType === 1) { // Sword self.swordGraphics.x = heroGraphics.width / 2 + Math.cos(aimAngle - self.rotation) * 20; self.swordGraphics.y = Math.sin(aimAngle - self.rotation) * 20; } else if (self.weaponType === 2) { // Bow self.bowGraphics.x = heroGraphics.width / 2; self.bowGraphics.rotation = 0; // Bow follows hero rotation } } } // Auto-attack system - continuously attack based on weapon type if (!isPopupActive) { if (self.attackCooldown > 0) { self.attackCooldown--; } // For sword attacks - only start a new attack if not already attacking and cooldown is complete if (self.weaponType === 1 && !self.isAttacking && self.attackCooldown <= 0) { // Start a new sword attack self.isAttacking = true; self.attackDurationCounter = self.attackDuration; // Track swing progress separately from cooldown } // For bow attacks if (self.weaponType === 2 && self.attackCooldown <= 0) { // Fire an arrow self.fireArrow(); self.attackCooldown = self.bowAttackSpeed; } } // Attack animation and logic for sword if (self.isAttacking) { // Track swing progress using a dedicated counter if (self.attackDurationCounter > 0) { self.attackDurationCounter--; } var swingProgress = (self.attackDuration - self.attackDurationCounter) / self.attackDuration; self.swordGraphics.rotation = Math.sin(swingProgress * Math.PI) * 1.2; self.swordGraphics.x = heroGraphics.width / 2 + Math.cos(swingProgress * Math.PI) * 30; self.swordGraphics.y = Math.sin(swingProgress * Math.PI) * 30; // End swing animation when appropriate if (swingProgress >= 1) { self.isAttacking = false; self.swordGraphics.rotation = 0; self.attackCooldown = self.swordAttackSpeed; // Only set cooldown after swing completes } else { // Check for enemies hit by sword during swing for (var i = currentRoom.enemies.length - 1; i >= 0; i--) { var enemy = currentRoom.enemies[i]; var angleToEnemy = Math.atan2(enemy.y - self.y, enemy.x - self.x); var angleDifference = Math.abs(angleToEnemy - self.rotation); var swordDx = enemy.x - (self.x + Math.cos(self.rotation) * self.attackRange); var swordDy = enemy.y - (self.y + Math.sin(self.rotation) * self.attackRange); var swordDistance = Math.sqrt(swordDx * swordDx + swordDy * swordDy); if (swordDistance < self.attackRange && angleDifference < Math.PI / 4) { enemy.health -= self.attackDamage; if (enemy.health <= 0) { currentRoom.enemiesKilled++; currentRoom.enemyCounter--; enemy.destroy(); currentRoom.enemies.splice(i, 1); updateRoomDisplay(); } } } } } else { self.swordGraphics.rotation = 0; } }; // Method to fire arrow in aimed direction self.fireArrow = function () { if (self.weaponType !== 2) { return; } // Only fire if bow is equipped var arrow = new Arrow(); arrow.x = self.x; arrow.y = self.y; // Use aiming joystick direction if available, otherwise use facing direction var fireDirection = self.aimingJoystick && self.aimingJoystick.hasInput() ? self.aimingJoystick.getRotation() : self.rotation; arrow.rotation = fireDirection; arrows.push(arrow); game.addChild(arrow); }; }); // Joystick class representing the on-screen joystick for movement var Joystick = Container.expand(function () { var self = Container.call(this); var joystickBackground = self.attachAsset('joystickBackground', { anchorX: 0.5, anchorY: 0.5 }); var joystickHandle = self.attachAsset('joystickHandle', { anchorX: 0.5, anchorY: 0.5 }); self.x = joystickBackground.width / 2 + 100; self.y = 2732 - joystickBackground.height / 2 - 100; var maxRadius = 100; var isDragging = false; self.down = function (x, y, obj) { isDragging = true; }; self.move = function (x, y, obj) { if (isDragging && !isPopupActive) { var localPos = self.toLocal(obj.global); var dx = localPos.x; var dy = localPos.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > maxRadius) { var angle = Math.atan2(dy, dx); dx = maxRadius * Math.cos(angle); dy = maxRadius * Math.sin(angle); } joystickHandle.x = dx; joystickHandle.y = dy; } }; self.up = function (x, y, obj) { isDragging = false; joystickHandle.x = 0; joystickHandle.y = 0; }; self.getDirection = function () { var magnitude = Math.sqrt(joystickHandle.x * joystickHandle.x + joystickHandle.y * joystickHandle.y); if (magnitude > 0) { return { x: joystickHandle.x / magnitude, y: joystickHandle.y / magnitude }; } return { x: 0, y: 0 }; }; return self; }); var Projectile = Container.expand(function () { var self = Container.call(this); self.attachAsset('ranged_attack', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 5; self.damage = 5; self.update = function () { self.x += self.vx; self.y += self.vy; self.rotation += 0.1; // Maintain spinning effect if (self.x < 0 || self.x > 2048 || self.y < 0 || self.y > 2732) { self.destroy(); } if (self.intersects(hero)) { hero.health -= self.damage; self.destroy(); updateRoomDisplay(); } }; return self; }); var RangedEnemy = Container.expand(function () { var self = Container.call(this); var rangedGraphics = self.attachAsset('ranged_run1', { anchorX: 0.5, anchorY: 0.5 }); var frames = [LK.getAsset('ranged_run1', { anchorX: 0.5, anchorY: 0.5 }), LK.getAsset('ranged_run2', { anchorX: 0.5, anchorY: 0.5 }), LK.getAsset('ranged_run3', { anchorX: 0.5, anchorY: 0.5 }), LK.getAsset('ranged_run4', { anchorX: 0.5, anchorY: 0.5 })]; self.speed = 2.0; self.health = 20; var currentFrame = 0; var frameDelay = 30; var frameCounter = 0; var projectileCooldown = 180; // 3 seconds at 60 FPS self.update = function () { frameCounter++; if (frameCounter >= frameDelay) { frameCounter = 0; self.removeChild(rangedGraphics); currentFrame = (currentFrame + 1) % frames.length; rangedGraphics = self.addChild(frames[currentFrame]); } var offsetX = (Math.random() - 0.5) * 20; var offsetY = (Math.random() - 0.5) * 20; var dx = hero.x + offsetX - self.x; var dy = hero.y + offsetY - self.y; var distance = Math.sqrt(dx * dx + dy * dy); var desiredDistance = 350; // Further increase the desired distance to maintain from the hero if (distance < desiredDistance) { self.x -= dx / distance * self.speed; self.y -= dy / distance * self.speed; } else if (distance > desiredDistance) { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; } self.rotation = Math.atan2(dy, dx); if (self.x < wallThickness) { self.x = wallThickness; } if (self.x > roomWidth - wallThickness) { self.x = roomWidth - wallThickness; } if (self.y < wallThickness) { self.y = wallThickness; } if (self.y > roomHeight - wallThickness) { self.y = roomHeight - wallThickness; } if (projectileCooldown <= 0) { self.shootProjectile(); projectileCooldown = 180; // Increase cooldown to 3 seconds at 60 FPS } else { projectileCooldown--; } }; self.shootProjectile = function () { var projectile = new Projectile('ranged_attack'); projectile.x = self.x; projectile.y = self.y; var targetX = hero.x; var targetY = hero.y; var dx = targetX - self.x; var dy = targetY - self.y; var angle = Math.atan2(dy, dx); projectile.rotation = angle; projectile.vx = Math.cos(angle) * projectile.speed; projectile.vy = Math.sin(angle) * projectile.speed; game.addChild(projectile); }; return self; }); // StartGameButton class representing the start game button functionality var StartGameButton = Container.expand(function () { var self = Container.call(this); self.attachAsset('startGameButton', { anchorX: 0.5, anchorY: 0.5, scaleX: 3, scaleY: 3 }); self.x = 2048 / 2; self.y = 2732 - 400; self.down = function () { menuContainer.removeChild(skillTreePopup); isPopupActive = false; isDataSpikePopupActive = false; initializeGame(); // Music is now handled in initializeGame -> playRoomMusic }; return self; }); var TankEnemy = Container.expand(function () { var self = Container.call(this); var tankGraphics = self.attachAsset('tank_run1', { anchorX: 0.5, anchorY: 0.5 }); var frames = [LK.getAsset('tank_run1', { anchorX: 0.5, anchorY: 0.5 }), LK.getAsset('tank_run2', { anchorX: 0.5, anchorY: 0.5 }), LK.getAsset('tank_run3', { anchorX: 0.5, anchorY: 0.5 }), LK.getAsset('tank_run4', { anchorX: 0.5, anchorY: 0.5 })]; self.speed = 1.0; self.health = 50; var currentFrame = 0; var frameDelay = 30; var frameCounter = 0; self.update = function () { frameCounter++; if (frameCounter >= frameDelay) { frameCounter = 0; self.removeChild(tankGraphics); currentFrame = (currentFrame + 1) % frames.length; tankGraphics = self.addChild(frames[currentFrame]); } // Movement logic similar to Enemy class var offsetX = (Math.random() - 0.5) * 20; var offsetY = (Math.random() - 0.5) * 20; var dx = hero.x + offsetX - self.x; var dy = hero.y + offsetY - self.y; var distance = Math.sqrt(dx * dx + dy * dy); var minDistance = 70; if (distance > minDistance) { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; self.rotation = Math.atan2(dy, dx); } if (self.x < wallThickness) { self.x = wallThickness; } if (self.x > roomWidth - wallThickness) { self.x = roomWidth - wallThickness; } if (self.y < wallThickness) { self.y = wallThickness; } if (self.y > roomHeight - wallThickness) { self.y = roomHeight - wallThickness; } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ function addDirectionalArrows() { var arrowDirections = ['top', 'bottom', 'left', 'right']; arrowDirections.forEach(function (direction) { var arrow = LK.getAsset('directionalArrow', { anchorX: 0.5, anchorY: 0.5 }); switch (direction) { case 'top': arrow.x = 2048 / 2; arrow.y = 500; arrow.rotation = 0; break; case 'bottom': arrow.x = 2048 / 2; arrow.y = 2732 - 500; arrow.rotation = Math.PI; break; case 'left': arrow.x = 500; arrow.y = 2732 / 2; arrow.rotation = -Math.PI / 2; break; case 'right': arrow.x = 2048 - 500; arrow.y = 2732 / 2; arrow.rotation = Math.PI / 2; break; } game.addChild(arrow); LK.effects.flashObject(arrow, 0xffffff, 1000); // Flash effect }); } function displayWhisperedStepsPopup() { var popup = createSkillPopup('Whispered Steps', 'Move silently, becoming harder to detect. Occasionally evade attacks entirely, as your footsteps blend into the ambient darkness.'); menuContainer.addChild(popup); isDataSpikePopupActive = true; } function displayNightfallVeilPopup() { var popup = createSkillPopup('Nightfall Veil', 'Briefly cloak yourself in shadow. While cloaked, project a faint silhouette to mislead foes. Attacks aimed at you may strike only empty air.'); menuContainer.addChild(popup); isDataSpikePopupActive = true; } function displaySerratedShadePopup() { var popup = createSkillPopup('Serrated Shade', 'Enhance your weapons with shadowy edges. Attacks may lacerate enemies, causing bleed-like damage over time as the darkness seeps into their wounds.'); menuContainer.addChild(popup); isDataSpikePopupActive = true; } function displayShadowFamiliarPopup() { var popup = createSkillPopup('Shadow Familiar', 'Summon a small, dark entity that assists you. It distracts enemies, occasionally nipping at their heels and granting you openings to strike.'); menuContainer.addChild(popup); isDataSpikePopupActive = true; } function displayMuffledStrikesPopup() { var popup = createSkillPopup('Muffled Strikes', 'Attacks produce little sound, reducing enemy awareness. Some foes fail to fully react, taking extra critical hits as they struggle to track your movements.'); menuContainer.addChild(popup); isDataSpikePopupActive = true; } function displayUmbralEchoesPopup() { var popup = createSkillPopup('Umbral Echoes', 'Your attacks leave lingering echoes of shadow. These echoes confuse enemies, causing them to strike illusions or hesitate, giving you more control in battle.'); menuContainer.addChild(popup); isDataSpikePopupActive = true; } function displayMidnightCrescendoPopup() { var popup = createSkillPopup('Midnight Crescendo', 'For a short duration, become one with the darkness. Your attacks ignore some armor, movement speed increases, and enemies are overwhelmed by disorienting echoes. A swirling concert of shadows amplifies your lethality.'); menuContainer.addChild(popup); isDataSpikePopupActive = true; } function displayChaoticSparkPopup() { var popup = createSkillPopup('Chaotic Spark', 'Your attacks sometimes produce random elemental effects. Damage types and minor status effects vary unpredictably, keeping foes off-balance.'); menuContainer.addChild(popup); isDataSpikePopupActive = true; } function displayEntropyShieldPopup() { var popup = createSkillPopup('Entropy Shield', 'Surround yourself with shifting energy fields. Each incoming hit has a chance to fizzle harmlessly or rebound, dealing random damage back to attackers.'); menuContainer.addChild(popup); isDataSpikePopupActive = true; } function displayUnstableRiftPopup() { var popup = createSkillPopup('Unstable Rift', 'Occasionally summon a pocket of chaos in battle. Enemies near the rift suffer random debuffs—slowing, poisoning, burning—ever-changing, never stable.'); menuContainer.addChild(popup); isDataSpikePopupActive = true; } function displayAnomalyShiftPopup() { var popup = createSkillPopup('Anomaly Shift', 'Briefly warp your form. Gain random beneficial buffs—from speed and regeneration to critical chance—but each application is uncertain, never guaranteed.'); menuContainer.addChild(popup); isDataSpikePopupActive = true; } function displayCascadeOfDisorderPopup() { var popup = createSkillPopup('Cascade of Disorder', 'Trigger a chain reaction of volatile energies. Attacks may ignite unpredictable chain effects, spreading to multiple enemies or amplifying certain strikes.'); menuContainer.addChild(popup); isDataSpikePopupActive = true; } function displayFracturedFatePopup() { var popup = createSkillPopup('Fractured Fate', 'Tap into temporal chaos. Sometimes attacks hit twice, or cooldowns shorten unexpectedly. Fate bends momentarily, granting you unpredictable bursts of advantage.'); menuContainer.addChild(popup); isDataSpikePopupActive = true; } function displayRealityCollapsePopup() { var popup = createSkillPopup('Reality Collapse', 'For a short time, unravel normal rules. Attacks ignore some defenses, enemies may lose control, and your random benefits intensify. Chaos reigns supreme, leaving foes disoriented and vulnerable.'); menuContainer.addChild(popup); isDataSpikePopupActive = true; } function displayRedRadiancePopup() { var popup = createSkillPopup('Red Radiance', 'Channel the crimson energy of aggression. Increases your attack damage slightly and grants a chance for attacks to ignite enemies, causing minor burn damage over time.'); menuContainer.addChild(popup); isDataSpikePopupActive = true; } function displayBlueBulwarkPopup() { var popup = createSkillPopup('Blue Bulwark', 'Embrace cerulean hues of defense. Enhances your armor and magic resistance for a short duration, reducing incoming damage and occasionally shielding you with a barrier of ice.'); menuContainer.addChild(popup); isDataSpikePopupActive = true; } function displayGreenGrowthPopup() { var popup = createSkillPopup('Green Growth', 'Tap into verdant life essence. Gradually regenerates a portion of your health and grants a chance for attacks to apply a minor heal-over-time effect to yourself or nearby allies.'); menuContainer.addChild(popup); isDataSpikePopupActive = true; } function displayYellowZephyrPopup() { var popup = createSkillPopup('Yellow Zephyr', 'Harness the swiftness of golden winds. Boosts your movement speed slightly and improves your bow’s draw rate or sword swing speed, letting you dart around combat swiftly.'); menuContainer.addChild(popup); isDataSpikePopupActive = true; } function displayIndigoInsightPopup() { var popup = createSkillPopup('Indigo Insight', 'Draw from deep indigo wisdom. Grants increased critical hit chance and a small probability to reflect a portion of incoming damage back at your attacker, showcasing keen foresight.'); menuContainer.addChild(popup); isDataSpikePopupActive = true; } function displayChromaticFusionPopup() { var popup = createSkillPopup('Chromatic Fusion', 'Blend two chosen elemental colors (e.g., Red and Blue) to create a hybrid effect. Depending on the combination, gain unique bonuses, such as fiery storms or frostburn effects, strengthening both offense and defense.'); menuContainer.addChild(popup); isDataSpikePopupActive = true; } function displayPrismaticAscendancePopup() { var popup = createSkillPopup('Prismatic Ascendance', 'Briefly harness all hues at once, greatly enhancing elemental power. Attacks may inflict multiple ailments, and you gain increased damage, defense, healing, and speed.'); menuContainer.addChild(popup); isDataSpikePopupActive = true; } function displayAdaptiveConstructionPopup() { var popup = createSkillPopup('Adaptive Construction', 'Learn to rapidly modify your weapons on the fly. Temporarily increase your sword or bow damage by 10% depending on which you wield most recently.'); menuContainer.addChild(popup); isDataSpikePopupActive = true; } function displayElementalInfusionPopup() { var popup = createSkillPopup('Elemental Infusion', 'Forge special arrowheads or blade edges with elemental cores. Each successful hit has a small chance to apply a random elemental effect to enemies.'); menuContainer.addChild(popup); isDataSpikePopupActive = true; } function displayModularEnhancementPopup() { var popup = createSkillPopup('Modular Enhancement', 'Attach versatile modules to your equipment. Gain a slight increase in attack speed and movement speed, allowing you to reposition more effectively during combat.'); menuContainer.addChild(popup); isDataSpikePopupActive = true; } function displayResourcefulSalvagePopup() { var popup = createSkillPopup('Resourceful Salvage', 'Disassemble enemy gear after defeats. Occasionally gain a temporary buff that slightly increases your skill point gain or reduces skill cooldowns.'); menuContainer.addChild(popup); isDataSpikePopupActive = true; } function displayHybridCraftingPopup() { var popup = createSkillPopup('Hybrid Crafting', 'Blend melee and ranged weapon traits. Your arrows gain a minor cleave effect at short range, and your sword attacks have a small chance to unleash a short-ranged projectile.'); menuContainer.addChild(popup); isDataSpikePopupActive = true; } function displayRunicSlotsPopup() { var popup = createSkillPopup('Runic Slots', 'Add runic slots to your weapons. When you acquire elemental shards from fallen foes, socketing them grants short-term buffs like increased critical chance, armor, or life steal.'); menuContainer.addChild(popup); isDataSpikePopupActive = true; } function displayMasterworkCreationPopup() { var popup = createSkillPopup('Masterwork Creation', 'Temporarily upgrade your weapon into a masterwork artifact. Significantly boosts both melee and ranged damage, and improves your elemental infusions for a short duration, turning you into a forging prodigy on the battlefield.'); menuContainer.addChild(popup); isDataSpikePopupActive = true; } function displayAncientWisdomPopup() { var popup = createSkillPopup('Ancient Wisdom', 'Tap into the deep knowledge of your forebears. Increases your critical hit chance by 5%.'); menuContainer.addChild(popup); isDataSpikePopupActive = true; } function displayElementalMasteryPopup() { var popup = createSkillPopup('Elemental Mastery', 'Channel elemental forces passed down through the ages. Your attacks gain a small amount of elemental damage, enhancing both sword and bow strikes.'); menuContainer.addChild(popup); isDataSpikePopupActive = true; } function displayWarriorSpiritPopup() { var popup = createSkillPopup('Warrior Spirit', 'Draw upon the martial prowess of ancestral warriors. Increases your melee attack speed by 10%, allowing swifter sword swings against foes.'); menuContainer.addChild(popup); isDataSpikePopupActive = true; } function displayBeastTamerPopup() { var popup = createSkillPopup('Beast Tamer', 'Ancestral bonds with nature grant you the ability to briefly call forth a spectral beast. This ally strikes nearby enemies before fading away.'); menuContainer.addChild(popup); isDataSpikePopupActive = true; } function displayHerbalRemediesPopup() { var popup = createSkillPopup('Herbal Remedies', 'Old herbal secrets provide gentle healing over time. Gradually restores a portion of your health while in battle.'); menuContainer.addChild(popup); isDataSpikePopupActive = true; } function displaySpiritGuidancePopup() { var popup = createSkillPopup('Spirit Guidance', 'A guiding ancestral spirit offers insight in combat. Reduces incoming damage by 5%, helping you withstand the harshest blows.'); menuContainer.addChild(popup); isDataSpikePopupActive = true; } function displayLegendaryAncestorPopup() { var popup = createSkillPopup('Legendary Ancestor', 'Invoke the essence of a mighty champion from your bloodline. For a short duration, greatly increase your overall damage and defense, turning the tide of battle in your favor.'); menuContainer.addChild(popup); isDataSpikePopupActive = true; } function updateSkillPointsDisplay() { if (typeof skillPointsDisplay !== 'undefined') { skillPointsDisplay.setText('Skill Points: ' + heroSkillPoints); } if (typeof skillPointsText !== 'undefined') { skillPointsText.setText('Skill Points: ' + heroSkillPoints); } } updateSkillPointsDisplay(); // call once to set initial text // Global variables var heroSkillPoints = 3; // Starting skill points var skillTreePointsText = null; // Will hold the text object once created // Define refreshTreePointsText globally so it's accessible everywhere function refreshTreePointsText() { if (skillTreePointsText) { skillTreePointsText.setText('Skill Points: ' + heroSkillPoints); } } var roomBackgroundImages = ['backgroundImage1', 'backgroundImage2', 'backgroundImage3', 'backgroundImage4', 'backgroundImage5']; var arrows = []; var currentRoom; var visitedRooms = []; var totalRooms = 5; // Assuming there are 5 rooms var currentRoomMusic; var hero; var isPopupActive = false; var isDataSpikePopupActive = false; var roomWidth = 2048; var roomHeight = 2732; var wallThickness = 400; var entranceWidth = 200; var entrances = { top: { xStart: (roomWidth - entranceWidth) / 2, xEnd: (roomWidth + entranceWidth) / 2, y: wallThickness }, bottom: { xStart: (roomWidth - entranceWidth) / 2, xEnd: (roomWidth + entranceWidth) / 2, y: roomHeight - wallThickness }, left: { yStart: (roomHeight - entranceWidth) / 2, yEnd: (roomHeight + entranceWidth) / 2, x: wallThickness }, right: { yStart: (roomHeight - entranceWidth) / 2, yEnd: (roomHeight + entranceWidth) / 2, x: roomWidth - wallThickness } }; var spawnPoints = { topLeft: { x: wallThickness, y: wallThickness }, topRight: { x: roomWidth - wallThickness, y: wallThickness }, bottomLeft: { x: wallThickness, y: roomHeight - wallThickness }, bottomRight: { x: roomWidth - wallThickness, y: roomHeight - wallThickness } }; var gameContainer = new Container(); var uiContainer = new Container(); var menuContainer = new Container(); game.addChild(gameContainer); game.addChild(uiContainer); game.addChild(menuContainer); var skillTreePopup = new Container(); skillTreePopup.width = 2048; skillTreePopup.height = 2732; skillTreePopup.x = 0; skillTreePopup.y = 0; var skillTreeBackground = LK.getAsset('skillTree_Background', { anchorX: 0.5, anchorY: 0.5 }); skillTreeBackground.x = 2048 / 2; skillTreeBackground.y = 2732 / 2; skillTreePopup.addChild(skillTreeBackground); // Add skill points display var skillPointsDisplay = new Text2('Skill Points: ' + heroSkillPoints, { size: 70, fill: 0xFFFFFF, fontWeight: "bold" }); skillPointsDisplay.x = 2048 / 2; // center horizontally skillPointsDisplay.y = 2732 - 100; // near bottom skillPointsDisplay.anchor.set(0.5, 0); skillTreePopup.addChild(skillPointsDisplay); var skillTrees = [{ title: 'The Circuit of Ascension', theme: 'Futuristic, cybernetic evolution' }, { title: 'The Echoes of Ancestry', theme: 'Mystical and historical' }, { title: 'The Forge of Possibilities', theme: 'Creative and modular' }, { title: 'The Prism of Potential', theme: 'Magical and elemental' }, { title: 'The Nexus of Chaos', theme: 'Unpredictable and chaotic' }, { title: 'The Symphony of Shadows', theme: 'Dark and stealth-focused' }]; var positions = [{ x: 1024 - 450, y: 1266 - 550 }, { x: 1024 + 450, y: 1266 - 550 }, { x: 1024 - 450, y: 1266 }, { x: 1024 + 450, y: 1266 }, { x: 1024 - 450, y: 1266 + 550 }, { x: 1024 + 450, y: 1266 + 550 }]; var skillTreeAssetMap = { 'The Circuit of Ascension': 'circuitofascension', 'The Echoes of Ancestry': 'echoesofancestry', 'The Forge of Possibilities': 'forgeofpossibilities', 'The Prism of Potential': 'prismofpotential', 'The Nexus of Chaos': 'nexusofchaos', 'The Symphony of Shadows': 'symphonyofshadows' }; positions.forEach(function (position, index) { var skillTree = skillTrees[index]; var titleText = new Text2(skillTree.title, { size: 50, fill: 0xFFFFFF, fontWeight: "bold", fontFamily: "Techno, sans-serif", letterSpacing: 2, stroke: 0x00FFCC, strokeThickness: 3 }); titleText.x = position.x; titleText.y = position.y + 200; titleText.anchor.set(0.5, 0); var skillTreeAssetId = skillTreeAssetMap[skillTree.title]; var skillTreeAsset = LK.getAsset(skillTreeAssetId, { anchorX: 0.5, anchorY: 0.5 }); if (!skillTreePopup.children.includes(skillTreeAsset)) { skillTreePopup.addChild(skillTreeAsset); } skillTreeAsset.x = position.x; skillTreeAsset.y = position.y; // Make the skill tree asset icon clickable skillTreeAsset.interactive = true; skillTreeAsset.down = function () { openSkillTreePopup(skillTree.title); }; if (!skillTreePopup.children.includes(skillTreeAsset)) { skillTreePopup.addChild(skillTreeAsset); } // Keep the title text clickable as well titleText.down = function () { openSkillTreePopup(skillTree.title); }; skillTreePopup.addChild(titleText); }); isPopupActive = true; menuContainer.addChild(skillTreePopup); var testRectangle = LK.getAsset('box', { anchorX: 0.5, anchorY: 0.5, width: 100, height: 50, color: 0xff0000 }); testRectangle.x = 100; testRectangle.y = 100; skillTreePopup.addChild(testRectangle); var startGameButton = new StartGameButton(); skillTreePopup.addChild(startGameButton); function initializeGame() { currentRoom = new Room(1); hero.x = 2048 / 2; hero.y = 2732 / 2; updateRoomDisplay(); playRoomMusic(currentRoom.number); } // Room class representing individual rooms var Room = function Room(number) { this.number = number; this.enemies = []; this.isCleared = false; this.spawnLimit = this.number === 1 ? 29 : 12 * this.number; this.killGoal = this.spawnLimit; this.enemiesSpawned = 0; this.enemiesKilled = 0; this.enemyCounter = this.spawnLimit; this.init = function () { var self = this; var spawnInterval = LK.setInterval(function () { if (self.enemiesSpawned < self.spawnLimit && currentRoom.number === self.number && !isPopupActive) { self.spawnEnemy(); } else { LK.clearInterval(spawnInterval); } }, 500); }; this.spawnEnemy = function () { if (this.enemiesSpawned < this.spawnLimit && !isPopupActive && currentRoom.number === this.number) { var spawnKeys = Object.keys(spawnPoints); var spawnIndex = Math.floor(Math.random() * spawnKeys.length); var spawnPoint = spawnPoints[spawnKeys[spawnIndex]]; var enemy; if (this.number === 1 && Math.random() < 5 / 29) { enemy = new TankEnemy(); } else if (this.number === 2) { if (Math.random() < 10 / 40) { enemy = new TankEnemy(); } else if (Math.random() < 5 / 40) { enemy = new RangedEnemy(); } else { enemy = new Enemy(); } } else { enemy = new Enemy(); } enemy.x = spawnPoint.x; enemy.y = spawnPoint.y; enemy.active = true; enemy.health = 10; enemy.visible = true; this.enemies.push(enemy); game.addChild(enemy); this.enemiesSpawned++; } }; this.init(); }; var initialBgImage = LK.getAsset('backgroundImage1', { anchorX: 0.5, anchorY: 0.5 }); initialBgImage.x = 2048 / 2; initialBgImage.y = 2732 / 2; game.addChildAt(initialBgImage, 0); game.background = initialBgImage; var statsBar = LK.getAsset('box', { anchorX: 0.0, anchorY: 0.0, width: 2048, height: 100, x: 0, y: 0 }); game.addChild(statsBar); var roomDisplay = new Text2('Room: 1 | Enemies Left: 0', { size: 70, fill: 0xFFFFFF, fontWeight: "bold" }); roomDisplay.x = 1000; roomDisplay.y = 20; game.addChild(roomDisplay); function updateRoomDisplay() { var enemiesLeft = currentRoom.spawnLimit - currentRoom.enemiesKilled; roomDisplay.setText('Room: ' + currentRoom.number + ' | Enemies Left: ' + Math.max(enemiesLeft, 0)); healthText.setText('Health: ' + hero.health); } function stopRoomMusic() { // Stop any playing music regardless of how it was started LK.stopMusic(); } function playRoomMusic(roomNumber) { // First stop any currently playing music stopRoomMusic(); // Always use LK.playMusic for consistency switch (roomNumber) { case 1: LK.playMusic('room1_music', { loop: true }); break; case 2: LK.playMusic('room2_music', { loop: true }); break; case 3: LK.playMusic('room3_music', { loop: true }); break; case 4: LK.playMusic('room4_music', { loop: true }); break; case 5: LK.playMusic('room5_music', { loop: true }); break; default: // Do nothing for default case } } function checkRoomCleared() { if (currentRoom.enemiesKilled >= currentRoom.killGoal && !currentRoom.isCleared) { // Play room cleared sound var roomClearedSound = LK.getSound('room' + currentRoom.number + '_cleared'); if (roomClearedSound) { roomClearedSound.play(); } // Stop the current room's music stopRoomMusic(); // Mark room as cleared and allow exit currentRoom.isCleared = true; hero.canExitRoom = true; updateRoomDisplay(); addDirectionalArrows(); } } function transitionToNextRoom() { // Remove the first call to playRoomMusic which was in the wrong place // Clean up the current room if (game.background) { game.removeChild(game.background); } // Clear all enemies currentRoom.enemies.forEach(function (enemy) { enemy.destroy(); }); currentRoom.enemies = []; currentRoom.enemiesSpawned = 0; currentRoom.enemyCounter = currentRoom.spawnLimit; currentRoom.enemiesKilled = 0; // Track visited rooms using array methods if (!visitedRooms.includes(currentRoom.number)) { visitedRooms.push(currentRoom.number); } // Find next room number var nextRoomNumber; do { nextRoomNumber = Math.floor(Math.random() * totalRooms) + 1; } while (visitedRooms.includes(nextRoomNumber) && visitedRooms.length < totalRooms); if (visitedRooms.length >= totalRooms) { // All rooms visited, reset for replayability visitedRooms = []; } // Initialize the new room currentRoom = new Room(nextRoomNumber); currentRoom.enemiesKilled = 0; // Set up background var bgImageIndex = (currentRoom.number - 1) % roomBackgroundImages.length; var bgImage = LK.getAsset(roomBackgroundImages[bgImageIndex], { anchorX: 0.5, anchorY: 0.5 }); bgImage.x = 2048 / 2; bgImage.y = 2732 / 2; game.addChildAt(bgImage, 0); game.background = bgImage; // Set room state currentRoom.isCleared = false; hero.canExitRoom = false; // Update UI updateRoomDisplay(); // Play the appropriate music for the new room playRoomMusic(currentRoom.number); } function transitionToNewRoom(entrySide) { // Position hero based on entry side if (entrySide === 'top') { hero.y = 2732 - 10; } else if (entrySide === 'bottom') { hero.y = 10; } else if (entrySide === 'left') { hero.x = 2048 - 10; } else if (entrySide === 'right') { hero.x = 10; } // Stop current music before transitioning stopRoomMusic(); // Set up the new room transitionToNextRoom(); // Play music for the new room - already called inside transitionToNextRoom hero.canExitRoom = false; } var hero = gameContainer.addChild(new Hero()); hero.x = 2048 / 2; hero.y = 2732 / 2; var healthText = new Text2('Health: ' + hero.health, { size: 70, fill: 0xFFFFFF, fontWeight: "bold" }); healthText.x = 300; healthText.y = 20; game.addChild(healthText); // Movement joystick (left side) var joystick = uiContainer.addChild(new Joystick()); joystick.x = joystick.width / 2 + 100; joystick.y = 2732 - joystick.height / 2 - 100; hero.joystick = joystick; // Aiming joystick (right side) var aimingJoystick = uiContainer.addChild(new AimingJoystick()); aimingJoystick.x = 2048 - aimingJoystick.width / 2 - 100; aimingJoystick.y = 2732 - aimingJoystick.height / 2 - 100; hero.aimingJoystick = aimingJoystick; var killAllButton = LK.getAsset('killAllButton', { anchorX: 0.5, anchorY: 0.5 }); killAllButton.x = 100; killAllButton.y = 2732 - 350; uiContainer.addChild(killAllButton); killAllButton.down = function (x, y, obj) { if (isPopupActive || isDataSpikePopupActive) { return; } for (var i = currentRoom.enemies.length - 1; i >= 0; i--) { var enemy = currentRoom.enemies[i]; enemy.destroy(); currentRoom.enemies.splice(i, 1); currentRoom.enemiesKilled++; } updateRoomDisplay(); checkRoomCleared(); updateRoomDisplay(); checkRoomCleared(); }; // Attack button removed - hero now attacks automatically var switchWeaponZone = LK.getAsset('switchWeaponZone', { anchorX: 0.5, anchorY: 0.5 }); switchWeaponZone.x = 2048 - switchWeaponZone.width / 2; switchWeaponZone.y = 2732 / 2; uiContainer.addChild(switchWeaponZone); game.down = function (x, y, obj) { if (isPopupActive) { return; } if (x >= switchWeaponZone.x - switchWeaponZone.width / 2 && x <= switchWeaponZone.x + switchWeaponZone.width / 2 && y >= switchWeaponZone.y - switchWeaponZone.height / 2 && y <= switchWeaponZone.y + switchWeaponZone.height / 2) { hero.weaponType = hero.weaponType === 1 ? 2 : 1; hero.swordGraphics.visible = hero.weaponType === 1; hero.bowGraphics.visible = hero.weaponType === 2; return; } }; game.update = function () { if (isPopupActive) { return; } // We now handle movement inside hero.update() rather than here hero.update(); if (hero.health <= 0) { hero.health = 0; LK.showGameOver(); return; } if (hero.canExitRoom) { if (hero.y < 10 || hero.y > 2732 - 10 || hero.x < 10 || hero.x > 2048 - 10) { var entrySide = hero.y < 10 ? 'bottom' : hero.y > 2732 - 10 ? 'top' : hero.x < 10 ? 'right' : 'left'; transitionToNewRoom(entrySide); } } // Update arrows for (var j = arrows.length - 1; j >= 0; j--) { arrows[j].update(); for (var i = currentRoom.enemies.length - 1; i >= 0; i--) { var hitDx = currentRoom.enemies[i].x - arrows[j].x; var hitDy = currentRoom.enemies[i].y - arrows[j].y; var hitDist = Math.sqrt(hitDx * hitDx + hitDy * hitDy); if (hitDist < 60) { currentRoom.enemies[i].health -= arrows[j].damage; if (currentRoom.enemies[i].health <= 0) { currentRoom.enemiesKilled++; currentRoom.enemyCounter--; if (currentRoom.enemies[i].parent) { currentRoom.enemies[i].parent.removeChild(currentRoom.enemies[i]); } currentRoom.enemies[i].destroy(); currentRoom.enemies.splice(i, 1); updateRoomDisplay(); } if (arrows[j]) { arrows[j].destroy(); arrows.splice(j, 1); } break; } } } // Update enemies if (!isPopupActive) { for (var k = 0; k < currentRoom.enemies.length; k++) { currentRoom.enemies[k].update(); } } checkRoomCleared(); }; function createSkillPopup(skillTitle, skillDescription) { var skillPopup = new Container(); skillPopup.width = 2048; skillPopup.height = 2732; skillPopup.x = 0; skillPopup.y = 0; var translucentBackground = LK.getAsset('box', { anchorX: 0.5, anchorY: 0.5, width: 2048, height: 2732, color: 0x000000, alpha: 0.5 }); translucentBackground.x = 2048 / 2; translucentBackground.y = 2732 / 2; skillPopup.addChild(translucentBackground); var skillTitleText = new Text2(skillTitle, { size: 120, fill: 0xFFFFFF, fontWeight: "bold", fontFamily: "Techno, sans-serif", letterSpacing: 2, stroke: 0x00FFCC, strokeThickness: 3 }); skillTitleText.x = 2048 / 2; skillTitleText.y = 2732 / 2 + 150 + 50; // Shifted down by 50 pixels skillTitleText.anchor.set(0.5, 0.5); skillPopup.addChild(skillTitleText); var skillDescriptionText = new Text2(skillDescription, { size: 80, fill: 0xFFFFFF, fontFamily: "Arial, sans-serif", letterSpacing: 1, stroke: 0x00FFCC, strokeThickness: 2, wordWrap: true, wordWrapWidth: 1800 }); skillDescriptionText.x = 2048 / 2; skillDescriptionText.y = skillTitleText.y + 300; // Position relative to shifted title skillDescriptionText.anchor.set(0.5, 0.5); skillPopup.addChild(skillDescriptionText); var exitButton = LK.getAsset('cancelButton', { anchorX: 0.5, anchorY: 0.5, scaleX: 3, scaleY: 3 }); exitButton.x = 2048 / 2 - 600; exitButton.y = 2732 / 2 + 950; // Shifted down by 100 pixels exitButton.down = function () { menuContainer.removeChild(skillPopup); isDataSpikePopupActive = false; }; skillPopup.addChild(exitButton); var spendButton = LK.getAsset('spendButton', { anchorX: 0.5, anchorY: 0.5, scaleX: 3, scaleY: 3 }); spendButton.x = 2048 / 2 + 600; spendButton.y = 2732 / 2 + 950; // Shifted down by 100 pixels function refreshSkillPointsText() { if (typeof skillPointsDisplay !== 'undefined') { skillPointsDisplay.setText('Skill Points: ' + heroSkillPoints); } if (typeof skillPointsText !== 'undefined') { skillPointsText.setText('Skill Points: ' + heroSkillPoints); } } spendButton.down = function () { if (heroSkillPoints > 0) { heroSkillPoints--; refreshSkillPointsText(); // Update text after spending refreshTreePointsText(); // Update tree points text if visible // Handle skill-specific point allocation if (skillTitle === 'Data Spike' && dataSpikePoints < dataSpikeMaxPoints) { dataSpikePoints++; // Close this popup and reopen it with updated description menuContainer.removeChild(skillPopup); isDataSpikePopupActive = false; displayDataSpikePopup(); return; // Exit early since we're reopening the popup } // Additional skill-specific logic can be added here for other skills } else { // No skill points left, optionally do nothing } }; skillPopup.addChild(spendButton); var skillPointsText = new Text2('Skill Points: ' + heroSkillPoints, { size: 70, fill: 0xFFFFFF, fontWeight: "bold" }); skillPointsText.x = 2048 / 2; skillPointsText.y = 2732 - 100; // bottom area of popup skillPointsText.anchor.set(0.5, 0); skillPopup.addChild(skillPointsText); return skillPopup; } function displayOverloadBlastPopup() { var overloadBlastPopup = createSkillPopup('Overload Blast', 'Unleashes a massive explosion that damages all enemies in the room.'); menuContainer.addChild(overloadBlastPopup); isDataSpikePopupActive = true; } function displayPowerSurgePopup() { var powerSurgePopup = createSkillPopup('Power Surge', 'Releases an energy burst that damages all nearby enemies.'); menuContainer.addChild(powerSurgePopup); isDataSpikePopupActive = true; } function displayDodgeMatrixPopup() { var dodgeMatrixPopup = createSkillPopup('Dodge Matrix', 'Grants a 10% chance to evade enemy attacks.'); menuContainer.addChild(dodgeMatrixPopup); isDataSpikePopupActive = true; } function displayNeuralHijackPopup() { var neuralHijackPopup = createSkillPopup('Neural Hijack', 'Temporarily converts an enemy to fight for you.'); menuContainer.addChild(neuralHijackPopup); isDataSpikePopupActive = true; } function displayOverclockCorePopup() { var overclockCorePopup = createSkillPopup('Overclock Core', 'Increases attack speed (2.5%) and energy regeneration by 2%.'); menuContainer.addChild(overclockCorePopup); isDataSpikePopupActive = true; } function displayReflexAcceleratorPopup() { var reflexAcceleratorPopup = createSkillPopup('Reflex Accelerator', 'Boosts movement speed by 10%.'); menuContainer.addChild(reflexAcceleratorPopup); isDataSpikePopupActive = true; } // Track skill point allocation for Data Spike var dataSpikePoints = 0; var dataSpikeMaxPoints = 5; var dataSpikeIncreases = [5, 4, 3, 2, 1]; // Diminishing returns function displayDataSpikePopup() { var currentBenefit = 0; // Calculate current benefit based on points allocated for (var i = 0; i < dataSpikePoints; i++) { currentBenefit += dataSpikeIncreases[i]; } // Show next increase if not maxed var description = ''; if (dataSpikePoints < dataSpikeMaxPoints) { var nextIncrease = dataSpikeIncreases[dataSpikePoints]; if (dataSpikePoints === 0) { description = 'Increases critical strike chance by 5%'; } else { description = 'Increases critical strike chance by ' + nextIncrease + '%. (Currently ' + currentBenefit + '%)'; } } else { description = 'Maximum rank reached. Your critical hit chance is increased by 15%.'; } var dataSpikePopup = createSkillPopup('Data Spike', description); menuContainer.addChild(dataSpikePopup); isDataSpikePopupActive = true; } function openSkillTreePopup(skillTreeName) { menuContainer.removeChild(skillTreePopup); var newPopup = new Container(); newPopup.width = 2048; newPopup.height = 2732; newPopup.x = 0; newPopup.y = 0; var newPopupBackground = LK.getAsset('skillTree_Background', { anchorX: 0.5, anchorY: 0.5 }); newPopupBackground.x = 2048 / 2; newPopupBackground.y = 2732 / 2; newPopup.addChild(newPopupBackground); if (skillTreeName === 'The Circuit of Ascension') { var circuitAsset = LK.getAsset('popup_circuitofascension', { anchorX: 0.5, anchorY: 0.5 }); circuitAsset.x = 2048 / 2; circuitAsset.y = 2732 / 2; newPopup.addChild(circuitAsset); var backButton = new BackButton(); newPopup.addChild(backButton); var skillNodes = [{ id: 'data_spike_icon', x: 2048 / 4 - 50, y: 2732 / 6 - 50 + 100, name: 'Data Spike' }, { id: 'reflex_accelerator_icon', x: 2048 / 2, y: 2732 / 6 - 50 + 100, name: 'Reflex Accelerator' }, { id: 'overclock_core_icon', x: 3 * 2048 / 4 + 50, y: 2732 / 6 - 50 + 100, name: 'Overclock Core' }, { id: 'neural_hijack_icon', x: 2048 / 4 - 50, y: 2 * 2732 / 6 + 100, name: 'Neural Hijack' }, { id: 'dodge_matrix_icon', x: 2048 / 2, y: 2 * 2732 / 6 + 100, name: 'Dodge Matrix' }, { id: 'power_surge_icon', x: 3 * 2048 / 4 + 50, y: 2 * 2732 / 6 + 100, name: 'Power Surge' }, { id: 'ultimate_skill_icon', x: 2048 / 2, y: 3 * 2732 / 6 + 50 + 100, name: 'Ultimate Skill' }]; skillNodes.forEach(function (node) { var skillNode = LK.getAsset(node.id, { anchorX: 0.5, anchorY: 0.5, scaleX: 3, scaleY: 3 }); skillNode.x = node.x; skillNode.y = node.y; // Add skill point allocation text below each node var pointsText = new Text2(node.name === 'Data Spike' ? dataSpikePoints + '/' + dataSpikeMaxPoints : '0/5', { size: 60, fill: 0xFFFFFF, fontWeight: "bold" }); pointsText.x = node.x; pointsText.y = node.y + 150; pointsText.anchor.set(0.5, 0); pointsText.alpha = 1; // Ensure text is visible and large enough newPopup.addChild(pointsText); // Create a node representation for the skillNode var nodeCircle = LK.getAsset('glowing_line_asset', { anchorX: 0.5, anchorY: 0.5, width: 60, height: 60, color: 0xc05bf1 }); nodeCircle.x = node.x; nodeCircle.y = node.y; newPopup.addChildAt(nodeCircle, 0); // Add below the skill icon skillNode.down = function () { if (isDataSpikePopupActive) { return; } if (node.name === 'Data Spike') { displayDataSpikePopup(); isDataSpikePopupActive = true; } else if (node.name === 'Overclock Core') { displayOverclockCorePopup(); isDataSpikePopupActive = true; } else if (node.name === 'Reflex Accelerator') { displayReflexAcceleratorPopup(); isDataSpikePopupActive = true; } else if (node.name === 'Neural Hijack') { displayNeuralHijackPopup(); isDataSpikePopupActive = true; } else if (node.name === 'Dodge Matrix') { displayDodgeMatrixPopup(); isDataSpikePopupActive = true; } else if (node.name === 'Power Surge') { displayPowerSurgePopup(); isDataSpikePopupActive = true; } else if (node.name === 'Ultimate Skill') { displayOverloadBlastPopup(); isDataSpikePopupActive = true; } var originalColor = skillNode.tint; skillNode.tint = 0xffff00; LK.setTimeout(function () { skillNode.tint = originalColor; }, 1000); }; newPopup.addChild(skillNode); }); } else if (skillTreeName === 'The Echoes of Ancestry') { var ancestryAsset = LK.getAsset('popup_echoesofancestry', { anchorX: 0.5, anchorY: 0.5 }); ancestryAsset.x = 2048 / 2; ancestryAsset.y = 2732 / 2; newPopup.addChild(ancestryAsset); var backButton = new BackButton(); newPopup.addChild(backButton); var skillNodes = [{ id: 'ancient_wisdom_icon', x: 2048 / 4 - 50, y: 2732 / 6 - 50 + 100, name: 'Ancient Wisdom' }, { id: 'elemental_mastery_icon', x: 2048 / 2, y: 2732 / 6 - 50 + 100, name: 'Elemental Mastery' }, { id: 'warrior_spirit_icon', x: 3 * 2048 / 4 + 50, y: 2732 / 6 - 50 + 100, name: 'Warrior Spirit' }, { id: 'beast_tamer_icon', x: 2048 / 4 - 50, y: 2 * 2732 / 6 + 100, name: 'Beast Tamer' }, { id: 'herbal_remedies_icon', x: 2048 / 2, y: 2 * 2732 / 6 + 100, name: 'Herbal Remedies' }, { id: 'spirit_guidance_icon', x: 3 * 2048 / 4 + 50, y: 2 * 2732 / 6 + 100, name: 'Spirit Guidance' }, { id: 'legendary_ancestor_icon', x: 2048 / 2, y: 3 * 2732 / 6 + 50 + 100, name: 'Legendary Ancestor' }]; skillNodes.forEach(function (node) { var skillNode = LK.getAsset(node.id, { anchorX: 0.5, anchorY: 0.5, scaleX: 3, scaleY: 3 }); skillNode.x = node.x; skillNode.y = node.y; // Add skill point allocation text below each node var pointsText = new Text2('0/5', { size: 60, fill: 0xFFFFFF, fontWeight: "bold" }); pointsText.x = node.x; pointsText.y = node.y + 150; pointsText.anchor.set(0.5, 0); pointsText.alpha = 1; // Ensure text is visible newPopup.addChild(pointsText); // Create a node representation for the skillNode var nodeCircle = LK.getAsset('glowing_line_asset', { anchorX: 0.5, anchorY: 0.5, width: 60, height: 60, color: 0xc05bf1 }); nodeCircle.x = node.x; nodeCircle.y = node.y; newPopup.addChildAt(nodeCircle, 0); // Add below the skill icon skillNode.down = function () { if (isDataSpikePopupActive) { return; } if (node.name === 'Ancient Wisdom') { displayAncientWisdomPopup(); } else if (node.name === 'Elemental Mastery') { displayElementalMasteryPopup(); } else if (node.name === 'Warrior Spirit') { displayWarriorSpiritPopup(); } else if (node.name === 'Beast Tamer') { displayBeastTamerPopup(); } else if (node.name === 'Herbal Remedies') { displayHerbalRemediesPopup(); } else if (node.name === 'Spirit Guidance') { displaySpiritGuidancePopup(); } else if (node.name === 'Legendary Ancestor') { displayLegendaryAncestorPopup(); } isDataSpikePopupActive = true; }; newPopup.addChild(skillNode); }); } else if (skillTreeName === 'The Forge of Possibilities') { var forgeAsset = LK.getAsset('popup_forgeofpossibilities', { anchorX: 0.5, anchorY: 0.5 }); forgeAsset.x = 2048 / 2; forgeAsset.y = 2732 / 2; newPopup.addChild(forgeAsset); var backButton = new BackButton(); newPopup.addChild(backButton); var skillNodes = [{ id: 'adaptive_construction_icon', x: 2048 / 4 - 50, y: 2732 / 6 - 50 + 100, name: 'Adaptive Construction' }, { id: 'elemental_infusion_icon', x: 2048 / 2, y: 2732 / 6 - 50 + 100, name: 'Elemental Infusion' }, { id: 'modular_enhancement_icon', x: 3 * 2048 / 4 + 50, y: 2732 / 6 - 50 + 100, name: 'Modular Enhancement' }, { id: 'resourceful_salvage_icon', x: 2048 / 4 - 50, y: 2 * 2732 / 6 + 100, name: 'Resourceful Salvage' }, { id: 'hybrid_crafting_icon', x: 2048 / 2, y: 2 * 2732 / 6 + 100, name: 'Hybrid Crafting' }, { id: 'runic_slots_icon', x: 3 * 2048 / 4 + 50, y: 2 * 2732 / 6 + 100, name: 'Runic Slots' }, { id: 'masterwork_creation_icon', x: 2048 / 2, y: 3 * 2732 / 6 + 50 + 100, name: 'Masterwork Creation' }]; skillNodes.forEach(function (node) { var skillNode = LK.getAsset(node.id, { anchorX: 0.5, anchorY: 0.5, scaleX: 3, scaleY: 3 }); skillNode.x = node.x; skillNode.y = node.y; // Add skill point allocation text below each node var pointsText = new Text2('0/5', { size: 60, fill: 0xFFFFFF, fontWeight: "bold" }); pointsText.x = node.x; pointsText.y = node.y + 150; pointsText.anchor.set(0.5, 0); pointsText.alpha = 1; // Ensure text is visible newPopup.addChild(pointsText); // Create a node representation for the skillNode var nodeCircle = LK.getAsset('glowing_line_asset', { anchorX: 0.5, anchorY: 0.5, width: 60, height: 60, color: 0xc05bf1 }); nodeCircle.x = node.x; nodeCircle.y = node.y; newPopup.addChildAt(nodeCircle, 0); // Add below the skill icon skillNode.down = function () { if (isDataSpikePopupActive) { return; } if (node.name === 'Adaptive Construction') { displayAdaptiveConstructionPopup(); } else if (node.name === 'Elemental Infusion') { displayElementalInfusionPopup(); } else if (node.name === 'Modular Enhancement') { displayModularEnhancementPopup(); } else if (node.name === 'Resourceful Salvage') { displayResourcefulSalvagePopup(); } else if (node.name === 'Hybrid Crafting') { displayHybridCraftingPopup(); } else if (node.name === 'Runic Slots') { displayRunicSlotsPopup(); } else if (node.name === 'Masterwork Creation') { displayMasterworkCreationPopup(); } isDataSpikePopupActive = true; }; newPopup.addChild(skillNode); }); } else if (skillTreeName === 'The Prism of Potential') { var prismAsset = LK.getAsset('popup_prismofpotential', { anchorX: 0.5, anchorY: 0.5 }); prismAsset.x = 2048 / 2; prismAsset.y = 2732 / 2; newPopup.addChild(prismAsset); var backButton = new BackButton(); newPopup.addChild(backButton); var skillNodes = [{ id: 'red_radiance_icon', x: 2048 / 4 - 50, y: 2732 / 6 - 50 + 100, name: 'Red Radiance' }, { id: 'blue_bulwark_icon', x: 2048 / 2, y: 2732 / 6 - 50 + 100, name: 'Blue Bulwark' }, { id: 'green_growth_icon', x: 3 * 2048 / 4 + 50, y: 2732 / 6 - 50 + 100, name: 'Green Growth' }, { id: 'yellow_zephyr_icon', x: 2048 / 4 - 50, y: 2 * 2732 / 6 + 100, name: 'Yellow Zephyr' }, { id: 'indigo_insight_icon', x: 2048 / 2, y: 2 * 2732 / 6 + 100, name: 'Indigo Insight' }, { id: 'chromatic_fusion_icon', x: 3 * 2048 / 4 + 50, y: 2 * 2732 / 6 + 100, name: 'Chromatic Fusion' }, { id: 'prismatic_ascendance_icon', x: 2048 / 2, y: 3 * 2732 / 6 + 50 + 100, name: 'Prismatic Ascendance' }]; skillNodes.forEach(function (node) { var skillNode = LK.getAsset(node.id, { anchorX: 0.5, anchorY: 0.5, scaleX: 3, scaleY: 3 }); skillNode.x = node.x; skillNode.y = node.y; // Add skill point allocation text below each node var pointsText = new Text2('0/5', { size: 60, fill: 0xFFFFFF, fontWeight: "bold" }); pointsText.x = node.x; pointsText.y = node.y + 150; pointsText.anchor.set(0.5, 0); pointsText.alpha = 1; // Ensure text is visible newPopup.addChild(pointsText); // Create a node representation for the skillNode var nodeCircle = LK.getAsset('glowing_line_asset', { anchorX: 0.5, anchorY: 0.5, width: 60, height: 60, color: 0xc05bf1 }); nodeCircle.x = node.x; nodeCircle.y = node.y; newPopup.addChildAt(nodeCircle, 0); // Add below the skill icon skillNode.down = function () { if (isDataSpikePopupActive) { return; } if (node.name === 'Red Radiance') { displayRedRadiancePopup(); } else if (node.name === 'Blue Bulwark') { displayBlueBulwarkPopup(); } else if (node.name === 'Green Growth') { displayGreenGrowthPopup(); } else if (node.name === 'Yellow Zephyr') { displayYellowZephyrPopup(); } else if (node.name === 'Indigo Insight') { displayIndigoInsightPopup(); } else if (node.name === 'Chromatic Fusion') { displayChromaticFusionPopup(); } else if (node.name === 'Prismatic Ascendance') { displayPrismaticAscendancePopup(); } isDataSpikePopupActive = true; }; newPopup.addChild(skillNode); }); } else if (skillTreeName === 'The Nexus of Chaos') { var nexusAsset = LK.getAsset('popup_nexusofchaos', { anchorX: 0.5, anchorY: 0.5 }); nexusAsset.x = 2048 / 2; nexusAsset.y = 2732 / 2; newPopup.addChild(nexusAsset); var backButton = new BackButton(); newPopup.addChild(backButton); var skillNodes = [{ id: 'chaotic_spark_icon', x: 2048 / 4 - 50, y: 2732 / 6 - 50 + 100, name: 'Chaotic Spark' }, { id: 'entropy_shield_icon', x: 2048 / 2, y: 2732 / 6 - 50 + 100, name: 'Entropy Shield' }, { id: 'unstable_rift_icon', x: 3 * 2048 / 4 + 50, y: 2732 / 6 - 50 + 100, name: 'Unstable Rift' }, { id: 'anomaly_shift_icon', x: 2048 / 4 - 50, y: 2 * 2732 / 6 + 100, name: 'Anomaly Shift' }, { id: 'cascade_of_disorder_icon', x: 2048 / 2, y: 2 * 2732 / 6 + 100, name: 'Cascade of Disorder' }, { id: 'fractured_fate_icon', x: 3 * 2048 / 4 + 50, y: 2 * 2732 / 6 + 100, name: 'Fractured Fate' }, { id: 'reality_collapse_icon', x: 2048 / 2, y: 3 * 2732 / 6 + 50 + 100, name: 'Reality Collapse' }]; skillNodes.forEach(function (node) { var skillNode = LK.getAsset(node.id, { anchorX: 0.5, anchorY: 0.5, scaleX: 3, scaleY: 3 }); skillNode.x = node.x; skillNode.y = node.y; // Add skill point allocation text below each node var pointsText = new Text2('0/5', { size: 60, fill: 0xFFFFFF, fontWeight: "bold" }); pointsText.x = node.x; pointsText.y = node.y + 150; pointsText.anchor.set(0.5, 0); pointsText.alpha = 1; // Ensure text is visible newPopup.addChild(pointsText); // Create a node representation for the skillNode var nodeCircle = LK.getAsset('glowing_line_asset', { anchorX: 0.5, anchorY: 0.5, width: 60, height: 60, color: 0xc05bf1 }); nodeCircle.x = node.x; nodeCircle.y = node.y; newPopup.addChildAt(nodeCircle, 0); // Add below the skill icon skillNode.down = function () { if (isDataSpikePopupActive) { return; } if (node.name === 'Chaotic Spark') { displayChaoticSparkPopup(); } else if (node.name === 'Entropy Shield') { displayEntropyShieldPopup(); } else if (node.name === 'Unstable Rift') { displayUnstableRiftPopup(); } else if (node.name === 'Anomaly Shift') { displayAnomalyShiftPopup(); } else if (node.name === 'Cascade of Disorder') { displayCascadeOfDisorderPopup(); } else if (node.name === 'Fractured Fate') { displayFracturedFatePopup(); } else if (node.name === 'Reality Collapse') { displayRealityCollapsePopup(); } isDataSpikePopupActive = true; }; newPopup.addChild(skillNode); }); } else if (skillTreeName === 'The Symphony of Shadows') { var symphonyAsset = LK.getAsset('popup_symphonyofshadows', { anchorX: 0.5, anchorY: 0.5 }); symphonyAsset.x = 2048 / 2; symphonyAsset.y = 2732 / 2; newPopup.addChild(symphonyAsset); var backButton = new BackButton(); newPopup.addChild(backButton); var skillNodes = [{ id: 'whispered_steps_icon', x: 2048 / 4 - 50, y: 2732 / 6 - 50 + 100, name: 'Whispered Steps' }, { id: 'nightfall_veil_icon', x: 2048 / 2, y: 2732 / 6 - 50 + 100, name: 'Nightfall Veil' }, { id: 'serrated_shade_icon', x: 3 * 2048 / 4 + 50, y: 2732 / 6 - 50 + 100, name: 'Serrated Shade' }, { id: 'shadow_familiar_icon', x: 2048 / 4 - 50, y: 2 * 2732 / 6 + 100, name: 'Shadow Familiar' }, { id: 'muffled_strikes_icon', x: 2048 / 2, y: 2 * 2732 / 6 + 100, name: 'Muffled Strikes' }, { id: 'umbral_echoes_icon', x: 3 * 2048 / 4 + 50, y: 2 * 2732 / 6 + 100, name: 'Umbral Echoes' }, { id: 'midnight_crescendo_icon', x: 2048 / 2, y: 3 * 2732 / 6 + 50 + 100, name: 'Midnight Crescendo' }]; skillNodes.forEach(function (node) { var skillNode = LK.getAsset(node.id, { anchorX: 0.5, anchorY: 0.5, scaleX: 3, scaleY: 3 }); skillNode.x = node.x; skillNode.y = node.y; // Add skill point allocation text below each node var pointsText = new Text2('0/5', { size: 60, fill: 0xFFFFFF, fontWeight: "bold" }); pointsText.x = node.x; pointsText.y = node.y + 150; pointsText.anchor.set(0.5, 0); pointsText.alpha = 1; // Ensure text is visible newPopup.addChild(pointsText); // Create a node representation for the skillNode var nodeCircle = LK.getAsset('glowing_line_asset', { anchorX: 0.5, anchorY: 0.5, width: 60, height: 60, color: 0xc05bf1 }); nodeCircle.x = node.x; nodeCircle.y = node.y; newPopup.addChildAt(nodeCircle, 0); // Add below the skill icon skillNode.down = function () { if (isDataSpikePopupActive) { return; } if (node.name === 'Whispered Steps') { displayWhisperedStepsPopup(); } else if (node.name === 'Nightfall Veil') { displayNightfallVeilPopup(); } else if (node.name === 'Serrated Shade') { displaySerratedShadePopup(); } else if (node.name === 'Shadow Familiar') { displayShadowFamiliarPopup(); } else if (node.name === 'Muffled Strikes') { displayMuffledStrikesPopup(); } else if (node.name === 'Umbral Echoes') { displayUmbralEchoesPopup(); } else if (node.name === 'Midnight Crescendo') { displayMidnightCrescendoPopup(); } isDataSpikePopupActive = true; }; newPopup.addChild(skillNode); }); } var skillTreeTitle = new Text2(skillTreeName, { size: 150, fill: 0xFFFFFF, fontWeight: "bold", fontFamily: "Techno, sans-serif", letterSpacing: 2, stroke: 0x00FFCC, strokeThickness: 3 }); skillTreeTitle.x = 2048 / 2; skillTreeTitle.y = 100; skillTreeTitle.anchor.set(0.5, 0); newPopup.addChild(skillTreeTitle); // Create the skillTreePointsText at the bottom of the skill tree popup skillTreePointsText = new Text2('Skill Points: ' + heroSkillPoints, { size: 70, fill: 0xFFFFFF, fontWeight: "bold" }); skillTreePointsText.x = 2048 / 2; skillTreePointsText.y = 2732 - 100; // bottom of the screen skillTreePointsText.anchor.set(0.5, 0); newPopup.addChild(skillTreePointsText); // Now that skillTreePointsText is defined, we can safely call refreshTreePointsText refreshTreePointsText(); menuContainer.addChild(newPopup); }
===================================================================
--- original.js
+++ change.js
@@ -1447,9 +1447,9 @@
var nextIncrease = dataSpikeIncreases[dataSpikePoints];
if (dataSpikePoints === 0) {
description = 'Increases critical strike chance by 5%';
} else {
- description = 'Each rank increases critical strike chance by ' + nextIncrease + '%. (Currently ' + currentBenefit + '%)';
+ description = 'Increases critical strike chance by ' + nextIncrease + '%. (Currently ' + currentBenefit + '%)';
}
} else {
description = 'Maximum rank reached. Your critical hit chance is increased by 15%.';
}
A round button with icons of a sword and bow crossed over a shield, hinting at weapon switching.. Game interface icon. Medieval theme with crossed weapons on a shield. High contrast and intuitive design.
A rugged medieval bow with a wooden frame and slightly frayed string, perfect for a fantasy setting.. Game asset. Rustic and worn. Medieval fantasy style. High detail with visible wood grain.
Remove the joystick stick
A dark, stone-walled dungeon chamber viewed directly from above. The floor is uneven with scattered bones and chains. Each wall has an entrance centered in the middle, like arched doorways, positioned on the top, bottom, left, and right sides. The room fills the entire frame, with torch-lit ambiance.. Full-frame, top-down view of a stone-walled dungeon chamber. Uneven floor, bones, chains, torch lighting. Open, arched entrances centered on each wall: top, bottom, left, and right. No 3D perspective, even lighting.
A high-tech command center with a glowing grid floor and sleek metallic walls. The room is viewed from directly above and has open entrances centered in the middle of each wall (top, bottom, left, and right) for easy transitions. Neon lights and holographic screens line the walls, casting a blue glow.. Full-frame, top-down view of a futuristic command center. Glowing grid floor, metallic walls, neon lights. Open entrances centered on each wall: top, bottom, left, and right. Blue glow, no perspective distortion.
A top-down view of jungle ruins with moss-covered stone walls and floors. The floor is scattered with vines and broken pillars. Each wall has an entrance centered in the middle, resembling natural archways positioned on the top, bottom, left, and right. Sunlight filters through, illuminating the room softly.. Full-frame, top-down view of jungle ruins. Moss-covered stone walls and floors, vines, broken pillars. Open natural archways centered on each wall: top, bottom, left, and right. Soft sunlight, no perspective distortion.
A pixelated skull with green digital "code streams" dripping down, symbolizing a destructive digital attack. Neon green and dark gray.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
A circular emblem with a tree at its center, its branches intertwining with a glowing red lineage symbol.. Colors: Deep red, gold, and subtle white highlights.
Elemental Gear Icon: A gear made of multiple materials (fire, ice, lightning, and shadow) fused together, symbolizing crafting hybrid powers.. Colors: Vibrant orange, blue, yellow, and dark purple.
Shattered Prism Icon: A cracked prism emitting chaotic light beams, symbolizing untapped magical potential.. Colors: Neon purple and silver with multicolored light fragments.
Fractured Sphere Icon: A glowing orb breaking apart into jagged, floating shards, with chaotic energy swirling around it.. Colors: Neon purple, black, and electric green.
Phantom Mask Icon: A mysterious, floating mask with glowing eyes and tendrils of shadow curling around it, symbolizing illusions and deception.. Colors: White mask with glowing blue accents and black shadows.
Backdrop: An ancient, mystical forest with glowing runes etched into massive tree trunks. Colors: Earthy greens and browns with soft golden accents. Details: Misty ambiance with faint ethereal figures in the background.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
Backdrop: A grand forge surrounded by molten lava and glowing hammers mid-swing. Colors: Fiery reds and oranges with metallic silver and gray. Details: Sparks flying and glowing weapon fragments scattered around.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
Backdrop: A crystal cavern with refracted light beams splitting into vibrant colors. Colors: Radiant rainbow hues with a soft, dark background. Details: Floating crystals and magical glowing particles.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
Backdrop: A warped reality scene with twisting, fragmented terrain and a swirling vortex in the background. Colors: Deep purples, neon pinks, and electric greens. Details: Fractured floating rocks and glitch-like patterns.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
Backdrop: A dark, shadowy realm with faint glowing outlines of jagged structures and flowing mist. Colors: Black, deep purples, and faint blue highlights. Details: Shadows shifting and subtle glowing runes.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
Weapon switch icon. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
Start game button. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
Big red kill button. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
Top-down view of a floating mechanical robot with a circular body. Thin, robotic arms extend outward, metallic and glowing. The head is small with glowing eyes. Strictly top-down view, no perspective or angle. Clean and detailed for 2D gameplay. Single Game Texture. In-Game asset. Top-down view. No shadows. 2D style. High contrast. Blank background.
A futuristic, top-down 2D game room featuring a minimalist industrial design. The room should have four distinct doorways at cardinal directions (up, down, left, and right). Each doorway should blend seamlessly into the room's aesthetic, with metallic frames and subtle glowing edges to indicate navigability. The room maintains its clean, tiled walls and floor, accented with industrial details like exposed pipes, vents, and panels. Lighting is ambient, with a mix of warm tones near the top and cooler tones along the walls. The overall theme is a high-tech but slightly weathered environment, ready for player navigation. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
A Dagger Icon with 1's and 0's dripping off of it like blood. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
A stylized, sleek cybernetic boot or leg silhouette with clear motion lines trailing behind it (like speed lines). Alternatively, three chevrons (>>>) pointing forward, glowing with blue energy, suggesting rapid advancement.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
Two stylized head silhouettes (one representing the hero, one the enemy) connected by arcing lines of digital energy or circuit patterns. Color could be a mix of blue (control) and maybe red/purple (target).. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
A shield shape formed from a 1's and 0's matrix pattern (like circuitry). Some lines of the grid could be missing or 'glitching' out, suggesting attacks passing through harmlessly. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
Concentric circles or energy waves expanding outwards from a central point. The waves could be depicted as sharp lines of light blue or white energy. Could also incorporate small lightning-like sparks within the surge.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
A more intense version of Power Surge. A fractured or exploding core shape at the center, emitting powerful, jagged energy waves (possibly in yellow or orange on top of blue). Could incorporate classic explosion symbol elements but rendered in the cybernetic style. Should look significantly more powerful than Power Surge.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
a cracked stone tablet or ancient scroll depicting elemental symbols with a subtle glow.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
A hand silhouette centrally placed, with symbolic representations of different elements (fire, ice/water, lightning/wind) swirling around it or emanating from the fingertips. Could also be intersecting elemental runes.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
A primal stone axe or spearhead with stylized speed lines or a spectral blue aura indicating swift movement.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
A glowing paw print (wolf, bear, or cat-like) leaving a faint spectral trail.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
A bundle of glowing green herbs tied together, or a single stylized leaf with potent green light radiating from its veins.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
a translucent, ghostly shield or a faint outline of a guardian spirit figure.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
An imposing, ornate tribal mask or helmet, perhaps with glowing eyes or runic carvings.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
A stylized hammer striking an anvil, creating fiery sparks or engulfing the hammer head in flames.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
A potion bottle or flask swirling with multiple distinct colors (red, blue, green).. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
A arrow and sword splitting into a double arrow and double sword signifying a extra shot/sword.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
Could also be a stylized recycling symbol combined with an upward arrow or a plus sign.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
A symbol merging a sword and an arrow/bow, perhaps crossing each other with energy flowing between them.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
A stylized metallic bracer or weapon hilt showing empty sockets being filled by small, glowing runes or gems.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
A glowing, ornate hammer imbued with power, or a weapon silhouette undergoing a visible transformation with radiating light and complex runic patterns.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
A sharp, faceted red crystal or gem shard glowing hotly.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
An angular, crystalline shield shimmering with blue light.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
Could also be a green crystal pulsing with soft light.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
A sharp, angular gust of wind symbol in bright yellow, or a stylized yellow feather.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
A sharply focused eye symbol in deep indigo color. Could also be a fractured mirror shard reflecting light, or an indigo crystal with internal sparks/light flashes.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
Two different colored streams of energy (e.g., red and blue) flowing and swirling together in the center. Could also be a crystal icon split into two distinct colors.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
A classic prism shape refracting a beam of white light into a rainbow spectrum. Could also be a figure surrounded by a swirling aura containing all the skill colors.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
A crackling spark of energy rapidly shifting between multiple colors (purple, green, orange). Could also be a die symbol with elemental icons instead of pips, or a weapon impact with a question mark.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
A shield shape that looks warped, dissolving at the edges, or made of static/glitches. Could show an arrow bouncing off at a weird angle or fizzling into nothing.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
A jagged tear or swirling vortex in space, leaking multi-colored, chaotic energy. Could incorporate shifting, abstract symbols or question marks within the rift.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
A silhouette of the hero glitching or flickering between different colors or slightly different forms. Could also be an upward arrow surrounded by swirling question marks or dice symbols.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
A branching pattern like lightning or cracks, but made of chaotic, multi-colored energy. Could also be a visual of one chaotic explosion triggering others nearby.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
A clock face or hourglass that is visibly cracked or shattering. Could also be a die symbol mid-roll or showing multiple faces at once.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
An imploding geometric shape or structure crumbling inwards into a chaotic void/vortex. Could be an intense version of the Unstable Rift, looking more menacing and powerful.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
A boot icon dissolving into smoke or shadow at the heel. Sound wave symbol with a line striking through it, indicating silence.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
A stylized cloak hood casting a deep shadow, with only faint eyes or nothing visible within. Could also be a figure splitting into a solid version and a shadowy decoy.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
A sharp, wicked-looking dagger or blade edge dripping with black, shadowy substance.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
A silhouette of a small, mischievous shadow creature (imp, tendril beast, raven?). Could also be a pair of glowing eyes peering out from darkness.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
A dagger or fist icon striking, but with sound waves around it being cancelled or muffled (e.g., crossed out or dissolving).. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
A central figure with several fading, translucent shadow copies trailing behind or positioned nearby. Could also be a weapon swing that leaves dark afterimages.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows