User prompt
make more permanent upgrades ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
it says that i get level 1 on bow upgrade even when i have perma upgrade
User prompt
make so the stars are filled and increace level ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
make the bow perma upgrade to start with a star depending on the level ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
make permanent upgrades bigger
User prompt
make it so when the upgrade is bought there is a new one like start with + 1 magnet ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
make only one permanent upgrade start with bow (1 star for each upgrade)
User prompt
remove the codes
User prompt
make a button for codes
User prompt
make max 10 waves
User prompt
make a permament upgrades button in the main menu
User prompt
change enemy hp per wave from 1.2x to 1.3x
User prompt
remove all stats and player in the main menu
User prompt
add a black screen in the beginning and at the bottom there is a play button
User prompt
change evolution I star 4 to +50% arrow damage
User prompt
add bow evolution I that works the same as magnet. evolution I = seeking arrows. seeks to enemys. star 1 = + 25 shoot speed. star 2 = + 20% arrow speed. star 3 = + 1 arrow. star 4 = + 50 arrow damage. star 5 = + 1 arrow.
User prompt
after picking magnet level 7 there are 2 yellow stars instead of 1. update this for every level after evolution
User prompt
remove the star that shows below the red star after level seven
User prompt
after picking magnet evolution there should only be filled a red star not a red and a yellow star
User prompt
make a yellow star for upgrades after evolution
User prompt
make the yellow star appear after level 6 instead of after evolution
User prompt
when the first evolution pops up the red star is already red. make the red star show after evolution is picked
User prompt
make magnet evolution not count as level 6. The levels go from 1-5 then evolution then 6-10
User prompt
when I have picked magnet level 6 or higher the yellow star does not appear
User prompt
make magnet level 6 (the one after evolution) + 25% magnet range. And from level 7 to 10 use + 20% pull speed
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Arrow = Container.expand(function () {
var self = Container.call(this);
var arrowGraphics = self.attachAsset('arrow', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 12;
self.damage = baseArrowDamage;
self.directionX = 0;
self.directionY = 0;
self.lastEnemyCollisions = [];
self.isSeeking = false;
self.setDirection = function (dx, dy) {
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
self.directionX = dx / distance;
self.directionY = dy / distance;
self.rotation = Math.atan2(dy, dx);
}
};
self.update = function () {
var actualSpeed = self.speed * arrowSpeedMultiplier;
// Seeking behavior if bow evolution is active
if (self.isSeeking && enemies.length > 0) {
var nearestEnemy = null;
var nearestDistance = Infinity;
for (var e = 0; e < enemies.length; e++) {
var enemy = enemies[e];
var dx = enemy.x - self.x;
var dy = enemy.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < nearestDistance) {
nearestDistance = distance;
nearestEnemy = enemy;
}
}
if (nearestEnemy) {
var dx = nearestEnemy.x - self.x;
var dy = nearestEnemy.y - self.y;
self.setDirection(dx, dy);
}
}
self.x += self.directionX * actualSpeed;
self.y += self.directionY * actualSpeed;
// Check collisions with enemies
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
var currentCollision = self.intersects(enemy);
var lastCollision = self.lastEnemyCollisions[i] || false;
if (!lastCollision && currentCollision) {
// Hit enemy
LK.getSound('enemyHit').play();
LK.effects.flashObject(enemy, 0xFFFFFF, 200);
// Damage enemy
var isDead = enemy.takeDamage(self.damage);
if (isDead) {
// Remove enemy
enemies.splice(i, 1);
enemy.destroy();
}
// Remove arrow
if (arrows.indexOf(self) !== -1) {
arrows.splice(arrows.indexOf(self), 1);
self.destroy();
}
return;
}
self.lastEnemyCollisions[i] = currentCollision;
}
};
return self;
});
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 1.5;
self.damage = 10;
self.targetX = 0;
self.targetY = 0;
self.lastPlayerCollision = false;
self.maxHealth = 30;
self.health = self.maxHealth;
// Create health bar background
var healthBarBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.15,
scaleY: 0.3
});
healthBarBg.y = -40;
// Create health bar
var healthBar = self.attachAsset('healthBar', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.15,
scaleY: 0.3
});
healthBar.y = -40;
self.healthBar = healthBar;
self.healthBarBg = healthBarBg;
self.update = function () {
// Don't move when game is paused for upgrades
if (gamePaused) return;
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
var currentCollision = self.intersects(player);
if (!self.lastPlayerCollision && currentCollision) {
player.takeDamage(self.damage);
}
self.lastPlayerCollision = currentCollision;
};
self.takeDamage = function (damage) {
self.health -= damage;
self.updateHealthBar();
if (self.health <= 0) {
self.health = 0;
// Drop XP orb
var xpOrb = new XPOrb();
xpOrb.x = self.x;
xpOrb.y = self.y;
xpOrbs.push(xpOrb);
game.addChild(xpOrb);
// Add tween animation for orb spawn
tween(xpOrb, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(xpOrb, {
scaleX: 1,
scaleY: 1
}, {
duration: 150,
easing: tween.easeIn
});
}
});
return true; // Enemy is dead
}
return false; // Enemy is still alive
};
self.updateHealthBar = function () {
var healthPercentage = self.health / self.maxHealth;
self.healthBar.scaleX = 0.15 * healthPercentage;
if (healthPercentage > 0.6) {
self.healthBar.tint = 0x4CAF50;
} else if (healthPercentage > 0.3) {
self.healthBar.tint = 0xFFEB3B;
} else {
self.healthBar.tint = 0xFF5722;
}
};
return self;
});
var FastEnemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('fastEnemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 3.0;
self.damage = 10;
self.targetX = 0;
self.targetY = 0;
self.lastPlayerCollision = false;
self.maxHealth = 24;
self.health = self.maxHealth;
// Create health bar background
var healthBarBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.12,
scaleY: 0.25
});
healthBarBg.y = -35;
// Create health bar
var healthBar = self.attachAsset('healthBar', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.12,
scaleY: 0.25
});
healthBar.y = -35;
self.healthBar = healthBar;
self.healthBarBg = healthBarBg;
self.update = function () {
// Don't move when game is paused for upgrades
if (gamePaused) return;
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
var currentCollision = self.intersects(player);
if (!self.lastPlayerCollision && currentCollision) {
player.takeDamage(self.damage);
}
self.lastPlayerCollision = currentCollision;
};
self.takeDamage = function (damage) {
self.health -= damage;
self.updateHealthBar();
if (self.health <= 0) {
self.health = 0;
// Drop XP orb
var xpOrb = new XPOrb();
xpOrb.x = self.x;
xpOrb.y = self.y;
xpOrbs.push(xpOrb);
game.addChild(xpOrb);
// Add tween animation for orb spawn
tween(xpOrb, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(xpOrb, {
scaleX: 1,
scaleY: 1
}, {
duration: 150,
easing: tween.easeIn
});
}
});
return true; // Enemy is dead
}
return false; // Enemy is still alive
};
self.updateHealthBar = function () {
var healthPercentage = self.health / self.maxHealth;
self.healthBar.scaleX = 0.12 * healthPercentage;
if (healthPercentage > 0.6) {
self.healthBar.tint = 0x4CAF50;
} else if (healthPercentage > 0.3) {
self.healthBar.tint = 0xFFEB3B;
} else {
self.healthBar.tint = 0xFF5722;
}
};
return self;
});
var HeavyEnemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('heavyEnemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 0.9; // Slower than regular enemies
self.damage = 15;
self.targetX = 0;
self.targetY = 0;
self.lastPlayerCollision = false;
self.maxHealth = 80; // More HP than regular enemies
self.health = self.maxHealth;
// Create health bar background
var healthBarBg = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.2,
scaleY: 0.35
});
healthBarBg.y = -50;
// Create health bar
var healthBar = self.attachAsset('healthBar', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.2,
scaleY: 0.35
});
healthBar.y = -50;
self.healthBar = healthBar;
self.healthBarBg = healthBarBg;
self.update = function () {
// Don't move when game is paused for upgrades
if (gamePaused) return;
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
var currentCollision = self.intersects(player);
if (!self.lastPlayerCollision && currentCollision) {
player.takeDamage(self.damage);
}
self.lastPlayerCollision = currentCollision;
};
self.takeDamage = function (damage) {
self.health -= damage;
self.updateHealthBar();
if (self.health <= 0) {
self.health = 0;
// Drop Yellow XP orb worth 3x normal XP
var xpOrb = new YellowXPOrb();
xpOrb.x = self.x;
xpOrb.y = self.y;
xpOrbs.push(xpOrb);
game.addChild(xpOrb);
// Add tween animation for orb spawn
tween(xpOrb, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(xpOrb, {
scaleX: 1,
scaleY: 1
}, {
duration: 150,
easing: tween.easeIn
});
}
});
return true; // Enemy is dead
}
return false; // Enemy is still alive
};
self.updateHealthBar = function () {
var healthPercentage = self.health / self.maxHealth;
self.healthBar.scaleX = 0.2 * healthPercentage;
if (healthPercentage > 0.6) {
self.healthBar.tint = 0x4CAF50;
} else if (healthPercentage > 0.3) {
self.healthBar.tint = 0xFFEB3B;
} else {
self.healthBar.tint = 0xFF5722;
}
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 100;
self.maxHealth = 100;
// Create player health bar background
var playerHealthBarBg = self.attachAsset('playerHealthBarBg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.6,
scaleY: 0.6
});
playerHealthBarBg.y = -50;
// Create player health bar
var playerHealthBar = self.attachAsset('playerHealthBar', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.6,
scaleY: 0.6
});
playerHealthBar.y = -50;
self.playerHealthBar = playerHealthBar;
self.playerHealthBarBg = playerHealthBarBg;
self.speed = 1;
self.invulnerable = false;
self.invulnerableTime = 0;
self.takeDamage = function (damage) {
if (self.invulnerable) {
return;
}
self.health -= damage;
self.updatePlayerHealthBar();
self.invulnerable = true;
self.invulnerableTime = 60; // 1 second of invulnerability
LK.getSound('playerDamage').play();
LK.effects.flashObject(self, 0xFF0000, 500);
if (self.health <= 0) {
self.health = 0;
gameOver = true;
}
};
self.heal = function (amount) {
self.health = Math.min(self.maxHealth, self.health + amount);
self.updatePlayerHealthBar();
};
self.updatePlayerHealthBar = function () {
var healthPercentage = self.health / self.maxHealth;
self.playerHealthBar.scaleX = 0.6 * healthPercentage;
if (healthPercentage > 0.6) {
self.playerHealthBar.tint = 0x4CAF50;
} else if (healthPercentage > 0.3) {
self.playerHealthBar.tint = 0xFFEB3B;
} else {
self.playerHealthBar.tint = 0xFF5722;
}
};
self.update = function () {
if (self.invulnerable) {
self.invulnerableTime--;
if (self.invulnerableTime <= 0) {
self.invulnerable = false;
}
}
};
return self;
});
var XPOrb = Container.expand(function () {
var self = Container.call(this);
var orbGraphics = self.attachAsset('xpOrb', {
anchorX: 0.5,
anchorY: 0.5
});
self.xpValue = 10;
self.attractDistance = baseMagnetRange;
self.attractSpeed = baseMagnetSpeed;
self.lastPlayerCollision = false;
self.update = function () {
// Don't attract when game is paused for upgrades
if (gamePaused) return;
// Check distance to player for attraction
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Attract to player if within range
if (distance < self.attractDistance && distance > 0) {
var moveSpeed = Math.min(self.attractSpeed, distance);
self.x += dx / distance * moveSpeed;
self.y += dy / distance * moveSpeed;
}
// Check collision with player
var currentCollision = self.intersects(player);
if (!self.lastPlayerCollision && currentCollision) {
// Collect XP
playerXP += self.xpValue;
checkLevelUp();
LK.getSound('xpCollect').play();
// Remove orb
if (xpOrbs.indexOf(self) !== -1) {
xpOrbs.splice(xpOrbs.indexOf(self), 1);
self.destroy();
}
}
self.lastPlayerCollision = currentCollision;
};
return self;
});
var YellowXPOrb = Container.expand(function () {
var self = Container.call(this);
var orbGraphics = self.attachAsset('yellowXpOrb', {
anchorX: 0.5,
anchorY: 0.5
});
self.xpValue = 30; // 3x the normal XP value (normal is 10)
self.attractDistance = baseMagnetRange;
self.attractSpeed = baseMagnetSpeed;
self.lastPlayerCollision = false;
self.update = function () {
// Don't attract when game is paused for upgrades
if (gamePaused) return;
// Check distance to player for attraction
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Yellow orbs need magnet evolution to be pulled at long range
// If player has magnet evolution (level 6+), use full attract distance
// Otherwise, use base magnet range (50) for yellow orbs
var effectiveAttractDistance = self.attractDistance;
if (upgradeLevels[5] < 6) {
// No magnet evolution - use base range for yellow orbs
effectiveAttractDistance = 50;
}
// Attract to player if within range
if (distance < effectiveAttractDistance && distance > 0) {
var moveSpeed = Math.min(self.attractSpeed, distance);
self.x += dx / distance * moveSpeed;
self.y += dy / distance * moveSpeed;
}
// Check collision with player
var currentCollision = self.intersects(player);
if (!self.lastPlayerCollision && currentCollision) {
// Collect XP
playerXP += self.xpValue;
checkLevelUp();
LK.getSound('xpCollect').play();
// Remove orb
if (xpOrbs.indexOf(self) !== -1) {
xpOrbs.splice(xpOrbs.indexOf(self), 1);
self.destroy();
}
}
self.lastPlayerCollision = currentCollision;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a1a1a
});
/****
* Game Code
****/
// Game state variables
var gameStarted = false;
var startScreen = null;
var playButton = null;
var upgradesScreen = null;
var upgradesScreenActive = false;
var upgradesScreenButtons = [];
// Create start screen
function createStartScreen() {
// Black background covering entire screen
startScreen = LK.getAsset('healthBarBg', {
anchorX: 0,
anchorY: 0,
scaleX: 12,
scaleY: 20
});
startScreen.x = 0;
startScreen.y = 0;
startScreen.tint = 0x000000;
game.addChild(startScreen);
// Play button
playButton = LK.getAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 4,
scaleY: 2
});
playButton.x = 1024;
playButton.y = 2200;
playButton.tint = 0x4CAF50;
game.addChild(playButton);
// Play button text
var playButtonText = new Text2('PLAY', {
size: 100,
fill: 0xFFFFFF
});
playButtonText.anchor.set(0.5, 0.5);
playButtonText.x = 1024;
playButtonText.y = 2200;
game.addChild(playButtonText);
// Store reference to text for cleanup
playButton.buttonText = playButtonText;
// Permanent upgrades button
var upgradesButton = LK.getAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 3,
scaleY: 1.5
});
upgradesButton.x = 1024;
upgradesButton.y = 2350;
upgradesButton.tint = 0xFF9800;
game.addChild(upgradesButton);
// Permanent upgrades button text
var upgradesButtonText = new Text2('UPGRADES', {
size: 60,
fill: 0xFFFFFF
});
upgradesButtonText.anchor.set(0.5, 0.5);
upgradesButtonText.x = 1024;
upgradesButtonText.y = 2350;
game.addChild(upgradesButtonText);
// Store references for cleanup
playButton.upgradesButton = upgradesButton;
playButton.upgradesButtonText = upgradesButtonText;
}
// Remove start screen and begin game
function startGame() {
if (startScreen) {
startScreen.destroy();
startScreen = null;
}
if (playButton) {
playButton.buttonText.destroy();
if (playButton.upgradesButton) {
playButton.upgradesButton.destroy();
playButton.upgradesButtonText.destroy();
}
playButton.destroy();
playButton = null;
}
// Apply permanent upgrades
baseArrowDamage += permanentUpgrades.damage * 5;
player.maxHealth += permanentUpgrades.health * 10;
player.health = player.maxHealth;
player.speed += permanentUpgrades.speed * 0.1;
player.updatePlayerHealthBar();
// Show UI elements and player
healthBarBg.visible = true;
healthBar.visible = true;
waveText.visible = true;
timeText.visible = true;
levelText.visible = true;
xpText.visible = true;
player.visible = true;
gameStarted = true;
}
// Permanent upgrades system
var permanentUpgrades = {
damage: storage.permanentDamage || 0,
health: storage.permanentHealth || 0,
speed: storage.permanentSpeed || 0,
coins: storage.coins || 0
};
function showUpgradesScreen() {
upgradesScreenActive = true;
// Clear existing buttons
clearUpgradesScreen();
// Black background
upgradesScreen = LK.getAsset('healthBarBg', {
anchorX: 0,
anchorY: 0,
scaleX: 12,
scaleY: 20
});
upgradesScreen.x = 0;
upgradesScreen.y = 0;
upgradesScreen.tint = 0x000000;
game.addChild(upgradesScreen);
upgradesScreenButtons.push(upgradesScreen);
// Title
var titleText = new Text2('PERMANENT UPGRADES', {
size: 80,
fill: 0xFFD700
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 400;
game.addChild(titleText);
upgradesScreenButtons.push(titleText);
// Coins display
var coinsText = new Text2('Coins: ' + permanentUpgrades.coins, {
size: 60,
fill: 0xFFFFFF
});
coinsText.anchor.set(0.5, 0.5);
coinsText.x = 1024;
coinsText.y = 500;
game.addChild(coinsText);
upgradesScreenButtons.push(coinsText);
// Upgrade buttons
var upgradeData = [{
name: 'Damage',
current: permanentUpgrades.damage,
cost: (permanentUpgrades.damage + 1) * 10,
key: 'damage'
}, {
name: 'Health',
current: permanentUpgrades.health,
cost: (permanentUpgrades.health + 1) * 15,
key: 'health'
}, {
name: 'Speed',
current: permanentUpgrades.speed,
cost: (permanentUpgrades.speed + 1) * 20,
key: 'speed'
}];
for (var i = 0; i < upgradeData.length; i++) {
var upgrade = upgradeData[i];
var buttonY = 700 + i * 200;
var canAfford = permanentUpgrades.coins >= upgrade.cost;
// Upgrade button
var upgradeButton = LK.getAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 8,
scaleY: 2
});
upgradeButton.x = 1024;
upgradeButton.y = buttonY;
upgradeButton.tint = canAfford ? 0x4CAF50 : 0x666666;
upgradeButton.upgradeKey = upgrade.key;
upgradeButton.upgradeCost = upgrade.cost;
game.addChild(upgradeButton);
upgradesScreenButtons.push(upgradeButton);
// Upgrade text
var upgradeText = new Text2(upgrade.name + ' Lv.' + upgrade.current, {
size: 70,
fill: 0xFFFFFF
});
upgradeText.anchor.set(0.5, 0.5);
upgradeText.x = 1024;
upgradeText.y = buttonY - 30;
game.addChild(upgradeText);
upgradesScreenButtons.push(upgradeText);
// Cost text
var costText = new Text2('Cost: ' + upgrade.cost, {
size: 50,
fill: canAfford ? 0xFFFFFF : 0x999999
});
costText.anchor.set(0.5, 0.5);
costText.x = 1024;
costText.y = buttonY + 30;
game.addChild(costText);
upgradesScreenButtons.push(costText);
}
// Back button
var backButton = LK.getAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 3,
scaleY: 1.5
});
backButton.x = 1024;
backButton.y = 2200;
backButton.tint = 0xFF5722;
backButton.isBackButton = true;
game.addChild(backButton);
upgradesScreenButtons.push(backButton);
var backButtonText = new Text2('BACK', {
size: 60,
fill: 0xFFFFFF
});
backButtonText.anchor.set(0.5, 0.5);
backButtonText.x = 1024;
backButtonText.y = 2200;
game.addChild(backButtonText);
upgradesScreenButtons.push(backButtonText);
}
function clearUpgradesScreen() {
for (var i = 0; i < upgradesScreenButtons.length; i++) {
upgradesScreenButtons[i].destroy();
}
upgradesScreenButtons = [];
}
function purchaseUpgrade(key, cost) {
if (permanentUpgrades.coins >= cost) {
permanentUpgrades.coins -= cost;
permanentUpgrades[key]++;
// Save to storage
storage.coins = permanentUpgrades.coins;
storage['permanent' + key.charAt(0).toUpperCase() + key.slice(1)] = permanentUpgrades[key];
// Refresh screen
showUpgradesScreen();
}
}
// Initialize start screen
createStartScreen();
var player = game.addChild(new Player());
player.x = 1024;
player.y = 1366;
player.visible = false;
player.updatePlayerHealthBar();
var enemies = [];
var arrows = [];
var xpOrbs = [];
var gameOver = false;
var lastShootTime = 0;
var shootCooldown = 90; // 50% slower shooting rate
var waveNumber = 1;
var enemiesSpawned = 0;
var enemiesPerWave = 5;
var spawnTimer = 0;
var survivalTime = 0;
var dragNode = null;
var playerXP = 0;
var playerLevel = 1;
var xpToNextLevel = 10;
var healthRegenTimer = 0;
var healthRegenCooldown = 60; // 60 ticks = 1 second at 60 FPS
var gamePaused = false;
var upgradeChoices = [];
var upgradeButtons = [];
var upgradeLevels = [0, 0, 0, 0, 0, 0, 0]; // Track levels for each upgrade type
// Base arrow damage that will be used for all new arrows
var baseArrowDamage = 15;
// Base magnet range that will be used for all new XP orbs
var baseMagnetRange = 50;
// Base magnet speed that will be used for all new XP orbs
var baseMagnetSpeed = 8;
// Bow upgrade variables
var arrowsPerBurst = 1;
var arrowSpeedMultiplier = 1.0;
var bowEvolutionActive = false;
// Keyboard input state
var keys = {
w: false,
a: false,
s: false,
d: false
};
// UI Elements
var healthBarBg = LK.getAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0
});
var healthBar = LK.getAsset('healthBar', {
anchorX: 0.5,
anchorY: 0
});
healthBarBg.visible = false;
healthBar.visible = false;
LK.gui.top.addChild(healthBarBg);
LK.gui.top.addChild(healthBar);
var waveText = new Text2('Wave: 1', {
size: 80,
fill: 0xFFFFFF
});
waveText.anchor.set(0.5, 0);
waveText.visible = false;
LK.gui.top.addChild(waveText);
var timeText = new Text2('Time: 0s', {
size: 60,
fill: 0xFFFFFF
});
timeText.anchor.set(1, 0);
timeText.visible = false;
LK.gui.topRight.addChild(timeText);
var levelText = new Text2('Level: 1', {
size: 70,
fill: 0xFFD700
});
levelText.anchor.set(0, 0);
levelText.visible = false;
LK.gui.topLeft.addChild(levelText);
var xpText = new Text2('XP: 0/10', {
size: 50,
fill: 0x00BCD4
});
xpText.anchor.set(0, 0);
xpText.visible = false;
LK.gui.topLeft.addChild(xpText);
// Position UI elements
healthBarBg.y = 120;
healthBar.y = 120;
waveText.y = 200;
timeText.y = 280;
timeText.x = -20;
levelText.x = 120;
levelText.y = 20;
xpText.x = 120;
xpText.y = 100;
function checkLevelUp() {
if (playerXP >= xpToNextLevel) {
playerLevel++;
playerXP -= xpToNextLevel;
xpToNextLevel = Math.floor(xpToNextLevel * 1.2);
// Level up effects
LK.effects.flashScreen(0xFFD700, 800);
player.heal(20);
// Pause game and show upgrade choices
gamePaused = true;
showUpgradeChoices();
}
}
function showUpgradeChoices() {
// Clear any existing upgrade choices
clearUpgradeChoices();
// Create upgrade background
var upgradeBackground = LK.getAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 8,
scaleY: 10
});
upgradeBackground.x = 1024;
upgradeBackground.y = 1366;
upgradeBackground.alpha = 0.9;
game.addChild(upgradeBackground);
upgradeButtons.push(upgradeBackground);
// Create title
var titleText = new Text2('LEVEL UP!', {
size: 100,
fill: 0xFFD700
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 1100;
game.addChild(titleText);
upgradeButtons.push(titleText);
// Define possible upgrades
var allUpgrades = [{
name: 'Health Boost',
description: '+20 Max Health',
index: 0,
effect: function effect() {
player.maxHealth += 20;
player.heal(20);
upgradeLevels[0]++;
}
}, {
name: 'Faster Shooting',
description: 'Shoot 25% Faster',
index: 1,
effect: function effect() {
shootCooldown = Math.max(30, shootCooldown - 15);
upgradeLevels[1]++;
}
}, {
name: 'More Damage',
description: '+50% Arrow Damage',
index: 2,
effect: function effect() {
baseArrowDamage = Math.floor(baseArrowDamage * 1.5);
upgradeLevels[2]++;
}
}, {
name: 'Speed Boost',
description: 'Move 20% Faster',
index: 3,
effect: function effect() {
player.speed += 0.2;
upgradeLevels[3]++;
}
}, {
name: 'Health Regen',
description: 'Heal 2HP per second',
index: 4,
effect: function effect() {
healthRegenCooldown = Math.max(20, healthRegenCooldown - 10);
upgradeLevels[4]++;
}
}, {
name: upgradeLevels[5] === 5 ? 'Magnet Evolution I' : 'Magnet',
description: getMagnetUpgradeDescription(),
index: 5,
effect: function effect() {
applyMagnetUpgrade();
upgradeLevels[5]++;
}
}, {
name: upgradeLevels[6] === 5 ? 'Bow Evolution I' : 'Bow Upgrade',
description: getBowUpgradeDescription(),
index: 6,
effect: function effect() {
applyBowUpgrade();
upgradeLevels[6]++;
}
}];
// Select 3 random upgrades, excluding those with 5 stars
upgradeChoices = [];
var availableUpgrades = [];
// Filter out upgrades that have reached maximum level (11 levels for magnet and bow, 5 for others)
for (var u = 0; u < allUpgrades.length; u++) {
var upgrade = allUpgrades[u];
var maxLevel = upgrade.index === 5 || upgrade.index === 6 ? 11 : 5; // Magnet and bow have 11 levels (6 + 5 evolution), others have 5
if (upgradeLevels[upgrade.index] < maxLevel) {
availableUpgrades.push(upgrade);
}
}
// If we have available upgrades, select up to 3 random ones
var upgradeCount = Math.min(3, availableUpgrades.length);
for (var i = 0; i < upgradeCount; i++) {
var randomIndex = Math.floor(Math.random() * availableUpgrades.length);
upgradeChoices.push(availableUpgrades[randomIndex]);
availableUpgrades.splice(randomIndex, 1);
}
// Create upgrade buttons
for (var i = 0; i < upgradeChoices.length; i++) {
var upgrade = upgradeChoices[i];
var buttonX = 350 + i * 700; // Horizontal spacing from left to right
var buttonY = 1330;
// Button background
var buttonBg = LK.getAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 6,
scaleY: 3
});
buttonBg.x = buttonX;
buttonBg.y = buttonY;
// Make button red if it's magnet or bow evolution level 5 (evolution I)
if (upgrade.index === 5 && upgradeLevels[5] === 5 || upgrade.index === 6 && upgradeLevels[6] === 5) {
buttonBg.tint = 0xCC0000;
buttonBg.alpha = 0.7; // Make evolution upgrade box darker
} else {
buttonBg.tint = 0x4CAF50;
}
buttonBg.upgradeIndex = i;
game.addChild(buttonBg);
upgradeButtons.push(buttonBg);
// Button text
var buttonText = new Text2(upgrade.name, {
size: 80,
fill: 0xFFFFFF
});
buttonText.anchor.set(0.5, 0.5);
buttonText.x = buttonX;
buttonText.y = buttonY - 30;
game.addChild(buttonText);
upgradeButtons.push(buttonText);
// Description text
var descText = new Text2(upgrade.description, {
size: 60,
fill: 0xCCCCCC
});
descText.anchor.set(0.5, 0.5);
descText.x = buttonX;
descText.y = buttonY + 30;
game.addChild(descText);
upgradeButtons.push(descText);
// Add stars below button
var upgradeLevel = upgradeLevels[upgrade.index];
var starY = buttonY + 100;
var maxStars = upgrade.index === 5 || upgrade.index === 6 ? 6 : 5; // Magnet and bow have 6 stars, others have 5
var starsToShow = maxStars;
// For magnet and bow upgrades, calculate display stars based on evolution
var displayStars = upgradeLevel;
if (upgrade.index === 5 || upgrade.index === 6) {
// For evolution upgrades: levels 7+ show as stars 1-5, but with 6th star visible
if (upgradeLevel >= 7) {
displayStars = upgradeLevel - 6; // Convert level 7+ to display stars 1-5 (level 7 = 1 star, level 8 = 2 stars, etc.)
starsToShow = 6; // Show 6 stars when in post-evolution (5 regular + 1 red)
} else if (upgradeLevel <= 5) {
starsToShow = 5; // Only show 5 stars before evolution
} else if (upgradeLevel === 6) {
displayStars = 0; // Evolution level shows as 0 stars filled
starsToShow = 6; // Show 6 stars including red one
}
}
for (var s = 0; s < starsToShow; s++) {
var star;
// Special handling for magnet and bow evolution (level 6 and above)
if ((upgrade.index === 5 || upgrade.index === 6) && upgradeLevel >= 6) {
// When evolution is active, the 6th star should always be red
if (s === 5) {
star = LK.getAsset('star', {
anchorX: 0.5,
anchorY: 0.5
});
star.tint = 0xFF0000; // Red color for evolution I
} else if (s < displayStars) {
// Show filled stars for current evolution level
star = LK.getAsset('star', {
anchorX: 0.5,
anchorY: 0.5
});
} else {
// Show dark stars for unfilled evolution levels
star = LK.getAsset('starDark', {
anchorX: 0.5,
anchorY: 0.5
});
}
} else if ((upgrade.index === 5 || upgrade.index === 6) && (upgradeLevel === 5 || upgradeLevel === 6)) {
// Special case for evolution being available or just picked - don't show red star for level 5, show it for level 6
if (s === 5) {
if (upgradeLevel === 6) {
// Show red star for level 6
star = LK.getAsset('star', {
anchorX: 0.5,
anchorY: 0.5
});
star.tint = 0xFF0000; // Red color for evolution I
} else {
// Don't show red star for level 5
star = LK.getAsset('starDark', {
anchorX: 0.5,
anchorY: 0.5
});
}
} else if (s < displayStars) {
star = LK.getAsset('star', {
anchorX: 0.5,
anchorY: 0.5
});
} else {
star = LK.getAsset('starDark', {
anchorX: 0.5,
anchorY: 0.5
});
}
} else {
// Normal star display logic for all other cases
if (s < displayStars) {
star = LK.getAsset('star', {
anchorX: 0.5,
anchorY: 0.5
});
} else {
star = LK.getAsset('starDark', {
anchorX: 0.5,
anchorY: 0.5
});
}
}
// Position stars - for magnet and bow (6 stars), put 6th star below first star
if ((upgrade.index === 5 || upgrade.index === 6) && s === 5) {
// 6th star for magnet/bow - position below the first star (star 0)
star.x = buttonX - 100 + 0 * 50; // Same x as first star
star.y = starY + 60; // Below the other stars
} else {
// Normal positioning for first 5 stars with increased spacing
star.x = buttonX - 100 + s * 50;
star.y = starY;
}
game.addChild(star);
upgradeButtons.push(star);
}
}
}
function getMagnetUpgradeDescription() {
var magnetLevel = upgradeLevels[5];
switch (magnetLevel) {
case 0:
case 1:
case 2:
case 3:
case 4:
return '+100% Magnet Range';
case 5:
return 'can pull yellow xp orbs';
case 6:
case 7:
case 8:
case 9:
case 10:
return '+25% Magnet Range';
case 11:
case 12:
case 13:
case 14:
return '+20% Pull Speed';
default:
return 'Max Level';
}
}
function getBowUpgradeDescription() {
var bowLevel = upgradeLevels[6];
switch (bowLevel) {
case 0:
return '+1 Arrow (Burst)';
case 1:
return '+100% Arrow Speed';
case 2:
return '+50% Arrow Damage';
case 3:
return '+25% Arrow Speed';
case 4:
return '+1 Arrow (Burst)';
case 5:
return 'seeking arrows';
case 6:
return '+25% Shoot Speed';
case 7:
return '+20% Arrow Speed';
case 8:
return '+1 Arrow';
case 9:
return '+50% Arrow Damage';
case 10:
return '+1 Arrow';
default:
return 'Max Level';
}
}
function applyMagnetUpgrade() {
var magnetLevel = upgradeLevels[5];
switch (magnetLevel) {
case 0:
case 1:
case 2:
case 3:
case 4:
// Levels 1-5: Double magnet range for all existing and future XP orbs
for (var o = 0; o < xpOrbs.length; o++) {
xpOrbs[o].attractDistance *= 2;
}
// Double base magnet range for new orbs
baseMagnetRange *= 2;
break;
case 5:
// Evolution: Double magnet pulling speed for all existing and future XP orbs
for (var o = 0; o < xpOrbs.length; o++) {
xpOrbs[o].attractSpeed *= 2;
}
// Double base magnet speed for new orbs
baseMagnetSpeed *= 2;
// Don't increment level for evolution - it stays at 5 until next upgrade
break;
case 6:
case 7:
case 8:
case 9:
case 10:
// Evolution level 6-10: +25% magnet range for all existing and future XP orbs
for (var o = 0; o < xpOrbs.length; o++) {
xpOrbs[o].attractDistance *= 1.25;
}
// +25% base magnet range for new orbs
baseMagnetRange *= 1.25;
break;
case 11:
case 12:
case 13:
case 14:
// Evolution levels 11-14: +20% pull speed for all existing and future XP orbs
for (var o = 0; o < xpOrbs.length; o++) {
xpOrbs[o].attractSpeed *= 1.2;
}
// +20% base magnet speed for new orbs
baseMagnetSpeed *= 1.2;
break;
}
}
function applyBowUpgrade() {
var bowLevel = upgradeLevels[6];
switch (bowLevel) {
case 0:
// Level 1: +1 arrow (burst)
arrowsPerBurst = 2;
break;
case 1:
// Level 2: +100% arrow speed
arrowSpeedMultiplier *= 2.0;
break;
case 2:
// Level 3: +50% arrow damage
baseArrowDamage = Math.floor(baseArrowDamage * 1.5);
break;
case 3:
// Level 4: +25% arrow speed
arrowSpeedMultiplier *= 1.25;
break;
case 4:
// Level 5: +1 arrow (burst)
arrowsPerBurst = 3;
break;
case 5:
// Evolution: seeking arrows
bowEvolutionActive = true;
break;
case 6:
// Evolution level 1: +25% shoot speed
shootCooldown = Math.floor(shootCooldown * 0.75);
break;
case 7:
// Evolution level 2: +20% arrow speed
arrowSpeedMultiplier *= 1.2;
break;
case 8:
// Evolution level 3: +1 arrow
arrowsPerBurst++;
break;
case 9:
// Evolution level 4: +50% arrow damage
baseArrowDamage = Math.floor(baseArrowDamage * 1.5);
break;
case 10:
// Evolution level 5: +1 arrow
arrowsPerBurst++;
break;
}
}
function clearUpgradeChoices() {
for (var i = 0; i < upgradeButtons.length; i++) {
upgradeButtons[i].destroy();
}
upgradeButtons = [];
upgradeChoices = [];
}
function selectUpgrade(index) {
if (index >= 0 && index < upgradeChoices.length) {
// Apply upgrade effect
upgradeChoices[index].effect();
// Clear upgrade UI
clearUpgradeChoices();
// Resume game
gamePaused = false;
}
}
function spawnEnemy() {
var enemy;
if (waveNumber >= 5 && Math.random() < 0.15) {
enemy = new HeavyEnemy();
} else if (waveNumber >= 3 && Math.random() < 0.3) {
enemy = new FastEnemy();
} else {
enemy = new Enemy();
}
var side = Math.floor(Math.random() * 4);
switch (side) {
case 0:
// Top
enemy.x = Math.random() * 2048;
enemy.y = -50;
break;
case 1:
// Right
enemy.x = 2098;
enemy.y = Math.random() * 2732;
break;
case 2:
// Bottom
enemy.x = Math.random() * 2048;
enemy.y = 2782;
break;
case 3:
// Left
enemy.x = -50;
enemy.y = Math.random() * 2732;
break;
}
enemy.targetX = player.x;
enemy.targetY = player.y;
enemy.speed += Math.floor(waveNumber / 3) * 0.5;
// Scale enemy health by 1.3x per wave
var healthMultiplier = Math.pow(1.3, waveNumber - 1);
enemy.maxHealth = Math.floor(enemy.maxHealth * healthMultiplier);
enemy.health = enemy.maxHealth;
enemy.updateHealthBar();
enemies.push(enemy);
game.addChild(enemy);
enemiesSpawned++;
}
function updateHealthBar() {
var healthPercentage = player.health / player.maxHealth;
healthBar.width = 400 * healthPercentage;
if (healthPercentage > 0.6) {
healthBar.tint = 0x4CAF50;
} else if (healthPercentage > 0.3) {
healthBar.tint = 0xFFEB3B;
} else {
healthBar.tint = 0xFF5722;
}
}
function handleMove(x, y, obj) {
if (dragNode && !gameOver) {
var newX = Math.max(40, Math.min(2008, x));
var newY = Math.max(40, Math.min(2692, y));
var dx = newX - dragNode.x;
var dy = newY - dragNode.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
var moveDistance = Math.min(distance, 8 * dragNode.speed);
dragNode.x += dx / distance * moveDistance;
dragNode.y += dy / distance * moveDistance;
}
}
}
game.move = handleMove;
game.down = function (x, y, obj) {
if (!gameStarted) {
if (upgradesScreenActive) {
// Handle upgrades screen clicks
for (var i = 0; i < upgradesScreenButtons.length; i++) {
var button = upgradesScreenButtons[i];
if (button.isBackButton) {
// Back button - return to main menu
var buttonWidth = 60 * 3;
var buttonHeight = 60 * 1.5;
var buttonLeft = button.x - buttonWidth / 2;
var buttonRight = button.x + buttonWidth / 2;
var buttonTop = button.y - buttonHeight / 2;
var buttonBottom = button.y + buttonHeight / 2;
if (x >= buttonLeft && x <= buttonRight && y >= buttonTop && y <= buttonBottom) {
upgradesScreenActive = false;
clearUpgradesScreen();
createStartScreen();
return;
}
} else if (button.upgradeKey) {
// Upgrade button
var buttonWidth = 60 * 8;
var buttonHeight = 60 * 2;
var buttonLeft = button.x - buttonWidth / 2;
var buttonRight = button.x + buttonWidth / 2;
var buttonTop = button.y - buttonHeight / 2;
var buttonBottom = button.y + buttonHeight / 2;
if (x >= buttonLeft && x <= buttonRight && y >= buttonTop && y <= buttonBottom) {
purchaseUpgrade(button.upgradeKey, button.upgradeCost);
return;
}
}
}
return;
}
// Check if play button was clicked
if (playButton) {
var buttonWidth = 60 * 4; // 240
var buttonHeight = 60 * 2; // 120
var buttonLeft = playButton.x - buttonWidth / 2;
var buttonRight = playButton.x + buttonWidth / 2;
var buttonTop = playButton.y - buttonHeight / 2;
var buttonBottom = playButton.y + buttonHeight / 2;
if (x >= buttonLeft && x <= buttonRight && y >= buttonTop && y <= buttonBottom) {
startGame();
return;
}
// Check if upgrades button was clicked
if (playButton.upgradesButton) {
var upgradesButtonWidth = 60 * 3;
var upgradesButtonHeight = 60 * 1.5;
var upgradesButtonLeft = playButton.upgradesButton.x - upgradesButtonWidth / 2;
var upgradesButtonRight = playButton.upgradesButton.x + upgradesButtonWidth / 2;
var upgradesButtonTop = playButton.upgradesButton.y - upgradesButtonHeight / 2;
var upgradesButtonBottom = playButton.upgradesButton.y + upgradesButtonHeight / 2;
if (x >= upgradesButtonLeft && x <= upgradesButtonRight && y >= upgradesButtonTop && y <= upgradesButtonBottom) {
// Hide start screen and show upgrades screen
if (startScreen) {
startScreen.destroy();
startScreen = null;
}
playButton.buttonText.destroy();
playButton.upgradesButton.destroy();
playButton.upgradesButtonText.destroy();
playButton.destroy();
playButton = null;
showUpgradesScreen();
return;
}
}
}
return;
}
if (!gameOver) {
// Check if we're in upgrade selection mode
if (gamePaused && upgradeButtons.length > 0) {
// Check if clicked on an upgrade button
for (var i = 0; i < upgradeButtons.length; i++) {
var button = upgradeButtons[i];
if (button.upgradeIndex !== undefined) {
// Check if click position is within button bounds
// Button is scaled 6x horizontally and 3x vertically from base enemy size (60x60)
var buttonWidth = 60 * 6; // 360
var buttonHeight = 60 * 3; // 180
var buttonLeft = button.x - buttonWidth / 2;
var buttonRight = button.x + buttonWidth / 2;
var buttonTop = button.y - buttonHeight / 2;
var buttonBottom = button.y + buttonHeight / 2;
if (x >= buttonLeft && x <= buttonRight && y >= buttonTop && y <= buttonBottom) {
selectUpgrade(button.upgradeIndex);
return;
}
}
}
} else {
dragNode = player;
handleMove(x, y, obj);
}
}
};
game.up = function (x, y, obj) {
dragNode = null;
};
// Keyboard event listeners
LK.on('keydown', function (event) {
switch (event.key.toLowerCase()) {
case 'w':
keys.w = true;
break;
case 'a':
keys.a = true;
break;
case 's':
keys.s = true;
break;
case 'd':
keys.d = true;
break;
}
});
LK.on('keyup', function (event) {
switch (event.key.toLowerCase()) {
case 'w':
keys.w = false;
break;
case 'a':
keys.a = false;
break;
case 's':
keys.s = false;
break;
case 'd':
keys.d = false;
break;
}
});
game.update = function () {
if (!gameStarted || gameOver) return;
// Check pause state before any updates
if (gamePaused) return;
survivalTime++;
// Handle WASD movement
var moveSpeed = 5;
if (keys.w) {
player.y = Math.max(40, player.y - moveSpeed);
}
if (keys.s) {
player.y = Math.min(2692, player.y + moveSpeed);
}
if (keys.a) {
player.x = Math.max(40, player.x - moveSpeed);
}
if (keys.d) {
player.x = Math.min(2008, player.x + moveSpeed);
}
// Health regeneration
healthRegenTimer++;
if (healthRegenTimer >= healthRegenCooldown && player.health < player.maxHealth) {
player.heal(1);
healthRegenTimer = 0;
}
// Update UI
updateHealthBar();
waveText.setText('Wave: ' + waveNumber);
timeText.setText('Time: ' + Math.floor(survivalTime / 60) + 's');
levelText.setText('Level: ' + playerLevel);
xpText.setText('XP: ' + playerXP + '/' + xpToNextLevel);
// Enemy spawning
spawnTimer++;
var spawnRate = Math.max(15, 60 - waveNumber * 3);
if (spawnTimer >= spawnRate && enemiesSpawned < enemiesPerWave) {
spawnEnemy();
spawnTimer = 0;
}
// Auto-shoot arrows at nearest enemy
lastShootTime++;
if (lastShootTime >= shootCooldown && enemies.length > 0) {
var nearestEnemy = null;
var nearestDistance = Infinity;
for (var e = 0; e < enemies.length; e++) {
var enemy = enemies[e];
var dx = enemy.x - player.x;
var dy = enemy.y - player.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < nearestDistance) {
nearestDistance = distance;
nearestEnemy = enemy;
}
}
if (nearestEnemy) {
var baseDx = nearestEnemy.x - player.x;
var baseDy = nearestEnemy.y - player.y;
// Fire multiple arrows in a burst
for (var b = 0; b < arrowsPerBurst; b++) {
// Add delay for burst arrows so they fire sequentially
if (b > 0) {
LK.setTimeout(function (burstIndex) {
return function () {
var arrow = new Arrow();
arrow.x = player.x;
arrow.y = player.y;
var dx = baseDx;
var dy = baseDy;
// All arrows fire in same direction
arrow.setDirection(dx, dy);
// Enable seeking if bow evolution is active
arrow.isSeeking = bowEvolutionActive;
arrows.push(arrow);
game.addChild(arrow);
};
}(b), b * 100); // 100ms delay between each arrow
} else {
// Fire first arrow immediately
var arrow = new Arrow();
arrow.x = player.x;
arrow.y = player.y;
var dx = baseDx;
var dy = baseDy;
// All arrows fire in same direction
arrow.setDirection(dx, dy);
// Enable seeking if bow evolution is active
arrow.isSeeking = bowEvolutionActive;
arrows.push(arrow);
game.addChild(arrow);
}
}
LK.getSound('arrowShoot').play();
lastShootTime = 0;
}
}
// Update arrows
for (var a = arrows.length - 1; a >= 0; a--) {
var arrow = arrows[a];
// Remove arrows that are off screen
if (arrow.x < -100 || arrow.x > 2148 || arrow.y < -100 || arrow.y > 2832) {
arrows.splice(a, 1);
arrow.destroy();
}
}
// Update XP orbs
for (var x = xpOrbs.length - 1; x >= 0; x--) {
var xpOrb = xpOrbs[x];
// Remove orbs that are too far off screen
if (xpOrb.x < -200 || xpOrb.x > 2248 || xpOrb.y < -200 || xpOrb.y > 2932) {
xpOrbs.splice(x, 1);
xpOrb.destroy();
}
}
// Update enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
enemy.targetX = player.x;
enemy.targetY = player.y;
// Remove enemies that are too far off screen
if (enemy.x < -200 || enemy.x > 2248 || enemy.y < -200 || enemy.y > 2932) {
enemies.splice(i, 1);
enemy.destroy();
}
}
// Check wave completion
if (enemiesSpawned >= enemiesPerWave && enemies.length === 0) {
waveNumber++;
enemiesSpawned = 0;
enemiesPerWave = Math.min(20, 5 + waveNumber * 2);
// Bonus health for completing wave
player.heal(10);
LK.effects.flashScreen(0x4CAF50, 500);
}
// Game over check
if (player.health <= 0) {
gameOver = true;
// Save best survival time
var bestTime = storage.bestTime || 0;
if (survivalTime > bestTime) {
storage.bestTime = survivalTime;
}
// Save total waves completed
var totalWaves = storage.totalWaves || 0;
storage.totalWaves = totalWaves + (waveNumber - 1);
// Award coins based on performance
var coinsEarned = Math.floor(survivalTime / 60) + (waveNumber - 1) * 5;
permanentUpgrades.coins += coinsEarned;
storage.coins = permanentUpgrades.coins;
LK.setScore(Math.floor(survivalTime / 60) + (waveNumber - 1) * 10);
LK.effects.flashScreen(0xFF0000, 1000);
LK.setTimeout(function () {
LK.showGameOver();
}, 1500);
}
}; ===================================================================
--- original.js
+++ change.js
@@ -526,8 +526,11 @@
// Game state variables
var gameStarted = false;
var startScreen = null;
var playButton = null;
+var upgradesScreen = null;
+var upgradesScreenActive = false;
+var upgradesScreenButtons = [];
// Create start screen
function createStartScreen() {
// Black background covering entire screen
startScreen = LK.getAsset('healthBarBg', {
@@ -561,8 +564,31 @@
playButtonText.y = 2200;
game.addChild(playButtonText);
// Store reference to text for cleanup
playButton.buttonText = playButtonText;
+ // Permanent upgrades button
+ var upgradesButton = LK.getAsset('enemy', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ scaleX: 3,
+ scaleY: 1.5
+ });
+ upgradesButton.x = 1024;
+ upgradesButton.y = 2350;
+ upgradesButton.tint = 0xFF9800;
+ game.addChild(upgradesButton);
+ // Permanent upgrades button text
+ var upgradesButtonText = new Text2('UPGRADES', {
+ size: 60,
+ fill: 0xFFFFFF
+ });
+ upgradesButtonText.anchor.set(0.5, 0.5);
+ upgradesButtonText.x = 1024;
+ upgradesButtonText.y = 2350;
+ game.addChild(upgradesButtonText);
+ // Store references for cleanup
+ playButton.upgradesButton = upgradesButton;
+ playButton.upgradesButtonText = upgradesButtonText;
}
// Remove start screen and begin game
function startGame() {
if (startScreen) {
@@ -570,11 +596,21 @@
startScreen = null;
}
if (playButton) {
playButton.buttonText.destroy();
+ if (playButton.upgradesButton) {
+ playButton.upgradesButton.destroy();
+ playButton.upgradesButtonText.destroy();
+ }
playButton.destroy();
playButton = null;
}
+ // Apply permanent upgrades
+ baseArrowDamage += permanentUpgrades.damage * 5;
+ player.maxHealth += permanentUpgrades.health * 10;
+ player.health = player.maxHealth;
+ player.speed += permanentUpgrades.speed * 0.1;
+ player.updatePlayerHealthBar();
// Show UI elements and player
healthBarBg.visible = true;
healthBar.visible = true;
waveText.visible = true;
@@ -583,8 +619,147 @@
xpText.visible = true;
player.visible = true;
gameStarted = true;
}
+// Permanent upgrades system
+var permanentUpgrades = {
+ damage: storage.permanentDamage || 0,
+ health: storage.permanentHealth || 0,
+ speed: storage.permanentSpeed || 0,
+ coins: storage.coins || 0
+};
+function showUpgradesScreen() {
+ upgradesScreenActive = true;
+ // Clear existing buttons
+ clearUpgradesScreen();
+ // Black background
+ upgradesScreen = LK.getAsset('healthBarBg', {
+ anchorX: 0,
+ anchorY: 0,
+ scaleX: 12,
+ scaleY: 20
+ });
+ upgradesScreen.x = 0;
+ upgradesScreen.y = 0;
+ upgradesScreen.tint = 0x000000;
+ game.addChild(upgradesScreen);
+ upgradesScreenButtons.push(upgradesScreen);
+ // Title
+ var titleText = new Text2('PERMANENT UPGRADES', {
+ size: 80,
+ fill: 0xFFD700
+ });
+ titleText.anchor.set(0.5, 0.5);
+ titleText.x = 1024;
+ titleText.y = 400;
+ game.addChild(titleText);
+ upgradesScreenButtons.push(titleText);
+ // Coins display
+ var coinsText = new Text2('Coins: ' + permanentUpgrades.coins, {
+ size: 60,
+ fill: 0xFFFFFF
+ });
+ coinsText.anchor.set(0.5, 0.5);
+ coinsText.x = 1024;
+ coinsText.y = 500;
+ game.addChild(coinsText);
+ upgradesScreenButtons.push(coinsText);
+ // Upgrade buttons
+ var upgradeData = [{
+ name: 'Damage',
+ current: permanentUpgrades.damage,
+ cost: (permanentUpgrades.damage + 1) * 10,
+ key: 'damage'
+ }, {
+ name: 'Health',
+ current: permanentUpgrades.health,
+ cost: (permanentUpgrades.health + 1) * 15,
+ key: 'health'
+ }, {
+ name: 'Speed',
+ current: permanentUpgrades.speed,
+ cost: (permanentUpgrades.speed + 1) * 20,
+ key: 'speed'
+ }];
+ for (var i = 0; i < upgradeData.length; i++) {
+ var upgrade = upgradeData[i];
+ var buttonY = 700 + i * 200;
+ var canAfford = permanentUpgrades.coins >= upgrade.cost;
+ // Upgrade button
+ var upgradeButton = LK.getAsset('enemy', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ scaleX: 8,
+ scaleY: 2
+ });
+ upgradeButton.x = 1024;
+ upgradeButton.y = buttonY;
+ upgradeButton.tint = canAfford ? 0x4CAF50 : 0x666666;
+ upgradeButton.upgradeKey = upgrade.key;
+ upgradeButton.upgradeCost = upgrade.cost;
+ game.addChild(upgradeButton);
+ upgradesScreenButtons.push(upgradeButton);
+ // Upgrade text
+ var upgradeText = new Text2(upgrade.name + ' Lv.' + upgrade.current, {
+ size: 70,
+ fill: 0xFFFFFF
+ });
+ upgradeText.anchor.set(0.5, 0.5);
+ upgradeText.x = 1024;
+ upgradeText.y = buttonY - 30;
+ game.addChild(upgradeText);
+ upgradesScreenButtons.push(upgradeText);
+ // Cost text
+ var costText = new Text2('Cost: ' + upgrade.cost, {
+ size: 50,
+ fill: canAfford ? 0xFFFFFF : 0x999999
+ });
+ costText.anchor.set(0.5, 0.5);
+ costText.x = 1024;
+ costText.y = buttonY + 30;
+ game.addChild(costText);
+ upgradesScreenButtons.push(costText);
+ }
+ // Back button
+ var backButton = LK.getAsset('enemy', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ scaleX: 3,
+ scaleY: 1.5
+ });
+ backButton.x = 1024;
+ backButton.y = 2200;
+ backButton.tint = 0xFF5722;
+ backButton.isBackButton = true;
+ game.addChild(backButton);
+ upgradesScreenButtons.push(backButton);
+ var backButtonText = new Text2('BACK', {
+ size: 60,
+ fill: 0xFFFFFF
+ });
+ backButtonText.anchor.set(0.5, 0.5);
+ backButtonText.x = 1024;
+ backButtonText.y = 2200;
+ game.addChild(backButtonText);
+ upgradesScreenButtons.push(backButtonText);
+}
+function clearUpgradesScreen() {
+ for (var i = 0; i < upgradesScreenButtons.length; i++) {
+ upgradesScreenButtons[i].destroy();
+ }
+ upgradesScreenButtons = [];
+}
+function purchaseUpgrade(key, cost) {
+ if (permanentUpgrades.coins >= cost) {
+ permanentUpgrades.coins -= cost;
+ permanentUpgrades[key]++;
+ // Save to storage
+ storage.coins = permanentUpgrades.coins;
+ storage['permanent' + key.charAt(0).toUpperCase() + key.slice(1)] = permanentUpgrades[key];
+ // Refresh screen
+ showUpgradesScreen();
+ }
+}
// Initialize start screen
createStartScreen();
var player = game.addChild(new Player());
player.x = 1024;
@@ -1180,8 +1355,42 @@
}
game.move = handleMove;
game.down = function (x, y, obj) {
if (!gameStarted) {
+ if (upgradesScreenActive) {
+ // Handle upgrades screen clicks
+ for (var i = 0; i < upgradesScreenButtons.length; i++) {
+ var button = upgradesScreenButtons[i];
+ if (button.isBackButton) {
+ // Back button - return to main menu
+ var buttonWidth = 60 * 3;
+ var buttonHeight = 60 * 1.5;
+ var buttonLeft = button.x - buttonWidth / 2;
+ var buttonRight = button.x + buttonWidth / 2;
+ var buttonTop = button.y - buttonHeight / 2;
+ var buttonBottom = button.y + buttonHeight / 2;
+ if (x >= buttonLeft && x <= buttonRight && y >= buttonTop && y <= buttonBottom) {
+ upgradesScreenActive = false;
+ clearUpgradesScreen();
+ createStartScreen();
+ return;
+ }
+ } else if (button.upgradeKey) {
+ // Upgrade button
+ var buttonWidth = 60 * 8;
+ var buttonHeight = 60 * 2;
+ var buttonLeft = button.x - buttonWidth / 2;
+ var buttonRight = button.x + buttonWidth / 2;
+ var buttonTop = button.y - buttonHeight / 2;
+ var buttonBottom = button.y + buttonHeight / 2;
+ if (x >= buttonLeft && x <= buttonRight && y >= buttonTop && y <= buttonBottom) {
+ purchaseUpgrade(button.upgradeKey, button.upgradeCost);
+ return;
+ }
+ }
+ }
+ return;
+ }
// Check if play button was clicked
if (playButton) {
var buttonWidth = 60 * 4; // 240
var buttonHeight = 60 * 2; // 120
@@ -1192,8 +1401,31 @@
if (x >= buttonLeft && x <= buttonRight && y >= buttonTop && y <= buttonBottom) {
startGame();
return;
}
+ // Check if upgrades button was clicked
+ if (playButton.upgradesButton) {
+ var upgradesButtonWidth = 60 * 3;
+ var upgradesButtonHeight = 60 * 1.5;
+ var upgradesButtonLeft = playButton.upgradesButton.x - upgradesButtonWidth / 2;
+ var upgradesButtonRight = playButton.upgradesButton.x + upgradesButtonWidth / 2;
+ var upgradesButtonTop = playButton.upgradesButton.y - upgradesButtonHeight / 2;
+ var upgradesButtonBottom = playButton.upgradesButton.y + upgradesButtonHeight / 2;
+ if (x >= upgradesButtonLeft && x <= upgradesButtonRight && y >= upgradesButtonTop && y <= upgradesButtonBottom) {
+ // Hide start screen and show upgrades screen
+ if (startScreen) {
+ startScreen.destroy();
+ startScreen = null;
+ }
+ playButton.buttonText.destroy();
+ playButton.upgradesButton.destroy();
+ playButton.upgradesButtonText.destroy();
+ playButton.destroy();
+ playButton = null;
+ showUpgradesScreen();
+ return;
+ }
+ }
}
return;
}
if (!gameOver) {
@@ -1401,8 +1633,12 @@
}
// Save total waves completed
var totalWaves = storage.totalWaves || 0;
storage.totalWaves = totalWaves + (waveNumber - 1);
+ // Award coins based on performance
+ var coinsEarned = Math.floor(survivalTime / 60) + (waveNumber - 1) * 5;
+ permanentUpgrades.coins += coinsEarned;
+ storage.coins = permanentUpgrades.coins;
LK.setScore(Math.floor(survivalTime / 60) + (waveNumber - 1) * 10);
LK.effects.flashScreen(0xFF0000, 1000);
LK.setTimeout(function () {
LK.showGameOver();