User prompt
Bosun atti mermileri hizini azalt saldiri hizini azalt
User prompt
1turdan sonra oyun durmasin random silah menusu gelmesin modelerine kadar sil
User prompt
Delete random weapon menu
User prompt
Tur sonu karakter yurumuyo bugu duzel artik duzelt lutfen duzelt
User prompt
Random silah secme menusunu sil
User prompt
1turdan sonra oyun donuyor devam etmiyor bu bugu duzelt ve rasgele silah menusunu sil
User prompt
Random silah secdiyimiz menuyu sil
User prompt
Silah secme menusunde silahlar ve yazilar arkada duruyor oneal
User prompt
Silah secme menusunu duzenli yap ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Random silah verme menusunu sil
User prompt
Silah secme menusunu modelle ve modellediyimiz sipahlari oyuna ekle modelleriyle ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Tur bitince random silah verme menusunu modelle ve oyuna ekle ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Markete petler ve zirh ekle buyu turleri ekle ve siniflara ayir
User prompt
Please fix the bug: 'TypeError: undefined is not an object (evaluating 'coinsText.setText')' in or related to this line: 'coinsText.setText('Coins: ' + currentCoins);' Line Number: 3666
User prompt
1turun sonunda rasgele silah verme menusunu tasarla ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Silahlari marketen silah secme menusuna aktar tum buglari fixle
User prompt
Silahlari markaten silah secme menusuna aktar
User prompt
Silahlari marketen cikart silah secme menusuna tasi
User prompt
Solahlarin hepsini ucretsiz yap
User prompt
Marketen paran yetsede silah alamiyosun bunu duzelt
User prompt
Pompaliyi kulanirlen oyun cok donuyor
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
highScore: 0,
totalKills: 0
});
/****
* Classes
****/
var BasicEnemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('basicEnemy', {
anchorX: 0.5,
anchorY: 0.5
});
// Weapon graphics removed
self.health = 25;
self.maxHealth = 25;
self.damage = 15;
self.speed = 2;
self.scoreValue = 10;
// Enemy hitbox properties
self.width = 240; // Enemy visual width
self.height = 240; // Enemy visual height
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xFFFFFF, 200);
if (self.health <= 0) {
// Drop XP orb
var xpOrb = new XPOrb();
xpOrb.x = self.x;
xpOrb.y = self.y;
xpOrbs.push(xpOrb);
game.addChild(xpOrb);
// 50% chance to drop coin
if (Math.random() < 0.5) {
var coin = new CoinPickup();
coin.x = self.x + (Math.random() - 0.5) * 60;
coin.y = self.y + (Math.random() - 0.5) * 60;
coinPickups.push(coin);
game.addChild(coin);
}
self.destroy();
LK.setScore(LK.getScore() + self.scoreValue);
scoreTxt.setText(LK.getScore());
LK.getSound('enemyDestroy').play();
for (var i = enemies.length - 1; i >= 0; i--) {
if (enemies[i] === self) {
enemies.splice(i, 1);
break;
}
}
}
};
// updateWeapon method removed
self.update = function () {
var dx = hero.x - self.x;
var dy = hero.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Weapon update removed
if (distance > 0) {
var newX = self.x + dx / distance * self.speed;
var newY = self.y + dy / distance * self.speed;
// Check collision with other enemies
var collisionFound = false;
for (var i = 0; i < enemies.length; i++) {
var otherEnemy = enemies[i];
if (otherEnemy !== self) {
var otherDx = newX - otherEnemy.x;
var otherDy = newY - otherEnemy.y;
var otherDistance = Math.sqrt(otherDx * otherDx + otherDy * otherDy);
var minDistance = (self.width + otherEnemy.width) / 4; // Collision threshold
if (otherDistance < minDistance) {
collisionFound = true;
// Push enemies apart
if (otherDistance > 0) {
var pushForce = (minDistance - otherDistance) / 2;
var pushX = otherDx / otherDistance * pushForce;
var pushY = otherDy / otherDistance * pushForce;
newX += pushX;
newY += pushY;
otherEnemy.x -= pushX;
otherEnemy.y -= pushY;
}
}
}
}
// Only move if no major collision or after separation
if (!collisionFound || distance > 100) {
self.x = newX;
self.y = newY;
}
}
};
return self;
});
var Boss = Container.expand(function () {
var self = Container.call(this);
var bossGraphics = self.attachAsset('wikingboss', {
anchorX: 0.5,
anchorY: 0.5
});
bossGraphics.tint = 0x8B4513; // Brown viking color
bossGraphics.scaleX = 4.0; // Much larger viking boss model
bossGraphics.scaleY = 4.0; // Much larger viking boss model
// Weapon graphics removed
// Add viking boss aura effect
var auraGraphics = self.attachAsset('wikingboss', {
anchorX: 0.5,
anchorY: 0.5
});
auraGraphics.tint = 0xDAA520; // Golden viking aura
auraGraphics.alpha = 0.4;
auraGraphics.scaleX = 4.5; // Larger aura to match viking boss size
auraGraphics.scaleY = 4.5; // Larger aura to match viking boss size
// Add pulsing viking aura animation
tween(auraGraphics, {
scaleX: 5.0,
scaleY: 5.0,
alpha: 0.2
}, {
duration: 1500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(auraGraphics, {
scaleX: 4.5,
scaleY: 4.5,
alpha: 0.4
}, {
duration: 1500,
easing: tween.easeInOut
});
}
});
self.health = 400 + (currentWave - 3) * 85; // Much higher health for viking boss
self.maxHealth = self.health;
self.damage = 70; // Higher damage for intimidating viking boss
self.speed = 0.8; // Slightly slower due to massive viking size
self.scoreValue = 250; // Higher reward for defeating viking boss
// Boss hitbox properties for accurate collision
self.width = 760; // Boss visual width (190 * 4 scale)
self.height = 760; // Boss visual height (190 * 4 scale)
self.lastLightningTime = 0;
self.lightningCooldown = 60; // 1 second at 60fps - much shorter for primary attack
self.lastChargeTime = 0;
self.chargeCooldown = 360; // 6 seconds at 60fps - less frequent
self.isCharging = false;
self.chargeSpeed = 8;
self.chargeTargetX = 0;
self.chargeTargetY = 0;
self.lastJumpTime = 0;
self.jumpCooldown = 300; // 5 seconds at 60fps - less frequent
self.isJumping = false;
self.jumpMarker = null;
self.lastAerialTime = 0;
self.aerialCooldown = 240; // 4 seconds at 60fps
self.isAerial = false;
self.aerialMarkers = [];
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xFFFFFF, 200);
if (self.health <= 0) {
// Drop multiple XP orbs
for (var orbCount = 0; orbCount < 5; orbCount++) {
var xpOrb = new XPOrb();
xpOrb.x = self.x + (Math.random() - 0.5) * 100;
xpOrb.y = self.y + (Math.random() - 0.5) * 100;
xpOrbs.push(xpOrb);
game.addChild(xpOrb);
}
// Boss always drops coins
for (var coinCount = 0; coinCount < 10; coinCount++) {
var coin = new CoinPickup();
coin.x = self.x + (Math.random() - 0.5) * 150;
coin.y = self.y + (Math.random() - 0.5) * 150;
coin.coinValue = 10; // Boss coins are worth more
coinPickups.push(coin);
game.addChild(coin);
}
self.destroy();
LK.setScore(LK.getScore() + self.scoreValue);
scoreTxt.setText(LK.getScore());
LK.getSound('enemyDestroy').play();
for (var i = enemies.length - 1; i >= 0; i--) {
if (enemies[i] === self) {
enemies.splice(i, 1);
break;
}
}
// Boss defeated - start new wave
LK.setTimeout(function () {
startNewWave();
}, 2000); // 2 second delay before starting new wave
}
};
self.shootBigBullets = function () {
// Create multiple big bullets - increased from 5 to 7 for more coverage
for (var bulletCount = 0; bulletCount < 7; bulletCount++) {
var bigBullet = new BossBullet();
bigBullet.x = self.x;
bigBullet.y = self.y;
// Spread bullets in a wider arc for better coverage
var angleOffset = (bulletCount - 3) * Math.PI / 10;
var targetX = hero.x + Math.cos(angleOffset) * 200;
var targetY = hero.y + Math.sin(angleOffset) * 200;
bigBullet.setTarget(targetX, targetY);
bossBullets.push(bigBullet);
game.addChild(bigBullet);
}
// More dramatic visual effect for primary attack
LK.effects.flashObject(self, 0xFF4500, 600);
LK.effects.flashScreen(0xFF4500, 100);
};
self.startCharge = function () {
self.isCharging = true;
self.chargeTargetX = hero.x;
self.chargeTargetY = hero.y;
LK.effects.flashObject(self, 0xFF4500, 500);
// Viking boss grows larger during charge
tween(bossGraphics, {
scaleX: 4.5,
scaleY: 4.5
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
// Charge for 1 second then return to normal
LK.setTimeout(function () {
self.isCharging = false;
tween(bossGraphics, {
scaleX: 4.0,
scaleY: 4.0
}, {
duration: 200,
easing: tween.easeIn
});
}, 1000);
}
});
};
self.startJumpAttack = function () {
self.isJumping = true;
// Create red marker at hero's position
self.jumpMarker = LK.getAsset('jumpMarker', {
anchorX: 0.5,
anchorY: 0.5
});
self.jumpMarker.x = hero.x;
self.jumpMarker.y = hero.y;
self.jumpMarker.alpha = 0.6;
game.addChild(self.jumpMarker);
// Pulse the marker
tween(self.jumpMarker, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 0.3
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(self.jumpMarker, {
scaleX: 1.0,
scaleY: 1.0,
alpha: 0.6
}, {
duration: 500,
easing: tween.easeInOut
});
}
});
// Boss prepares to jump - crouch animation
tween(bossGraphics, {
scaleY: 3.5
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {
// Jump to marker position
var jumpX = self.jumpMarker.x;
var jumpY = self.jumpMarker.y;
// Jump animation
tween(self, {
x: jumpX,
y: jumpY
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
// Landing impact
LK.effects.flashScreen(0xFF0000, 200);
tween(bossGraphics, {
scaleY: 4.0
}, {
duration: 200,
easing: tween.easeOut
});
// Deal area damage at landing position
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
if (enemy !== self) {
var impactDx = enemy.x - self.x;
var impactDy = enemy.y - self.y;
var impactDistance = Math.sqrt(impactDx * impactDx + impactDy * impactDy);
if (impactDistance < 250) {
enemy.takeDamage(40);
}
}
}
// Check if hero is in impact area
var heroDx = hero.x - self.x;
var heroDy = hero.y - self.y;
var heroDistance = Math.sqrt(heroDx * heroDx + heroDy * heroDy);
if (heroDistance < 250) {
hero.takeDamage(60);
}
// Remove marker
if (self.jumpMarker) {
self.jumpMarker.destroy();
self.jumpMarker = null;
}
self.isJumping = false;
}
});
}
});
};
self.startAerialAttack = function () {
self.isAerial = true;
// Create multiple red markers in a pattern around hero
var markerCount = 5;
for (var i = 0; i < markerCount; i++) {
var angle = Math.PI * 2 / markerCount * i;
var markerDistance = 150;
var marker = LK.getAsset('jumpMarker', {
anchorX: 0.5,
anchorY: 0.5
});
marker.x = hero.x + Math.cos(angle) * markerDistance;
marker.y = hero.y + Math.sin(angle) * markerDistance;
marker.alpha = 0.8;
marker.tint = 0xFF0000;
game.addChild(marker);
self.aerialMarkers.push(marker);
// Pulse animation for markers
tween(marker, {
scaleX: 1.3,
scaleY: 1.3,
alpha: 0.4
}, {
duration: 400,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(marker, {
scaleX: 1.0,
scaleY: 1.0,
alpha: 0.8
}, {
duration: 400,
easing: tween.easeInOut
});
}
});
}
// Boss rises up animation
tween(bossGraphics, {
scaleX: 3.5,
scaleY: 3.5,
alpha: 0.5
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
// After delay, rain bullets from sky
LK.setTimeout(function () {
// Create bullets at each marker position
for (var j = 0; j < self.aerialMarkers.length; j++) {
var targetMarker = self.aerialMarkers[j];
// Create bullet high above
var skyBullet = new BossBullet();
skyBullet.x = targetMarker.x;
skyBullet.y = targetMarker.y - 800; // Start high above
skyBullet.setTarget(targetMarker.x, targetMarker.y);
bossBullets.push(skyBullet);
game.addChild(skyBullet);
}
// Boss returns to normal
tween(bossGraphics, {
scaleX: 4.0,
scaleY: 4.0,
alpha: 1.0
}, {
duration: 300,
easing: tween.easeIn
});
// Remove markers after bullets are fired
for (var k = 0; k < self.aerialMarkers.length; k++) {
self.aerialMarkers[k].destroy();
}
self.aerialMarkers = [];
self.isAerial = false;
}, 800);
}
});
};
self.update = function () {
var dx = hero.x - self.x;
var dy = hero.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var currentTime = LK.ticks;
// Weapon update removed
// Big bullet attack - primary attack with extended range
if (distance < 900 && currentTime - self.lastLightningTime > self.lightningCooldown) {
self.shootBigBullets();
self.lastLightningTime = currentTime;
}
// Charge attack - secondary attack, less frequent
if (distance > 250 && distance < 600 && currentTime - self.lastChargeTime > self.chargeCooldown && !self.isCharging && !self.isJumping) {
self.startCharge();
self.lastChargeTime = currentTime;
}
// Jump attack - tertiary attack, least frequent
if (distance < 700 && currentTime - self.lastJumpTime > self.jumpCooldown && !self.isJumping && !self.isCharging && !self.isAerial) {
self.startJumpAttack();
self.lastJumpTime = currentTime;
}
// Aerial attack - quaternary attack
if (distance < 600 && currentTime - self.lastAerialTime > self.aerialCooldown && !self.isJumping && !self.isCharging && !self.isAerial) {
self.startAerialAttack();
self.lastAerialTime = currentTime;
}
// Movement behavior
if (self.isCharging) {
// Charge towards target position
var chargeDx = self.chargeTargetX - self.x;
var chargeDy = self.chargeTargetY - self.y;
var chargeDistance = Math.sqrt(chargeDx * chargeDx + chargeDy * chargeDy);
if (chargeDistance > 0) {
self.x += chargeDx / chargeDistance * self.chargeSpeed;
self.y += chargeDy / chargeDistance * self.chargeSpeed;
}
} else if (self.isJumping || self.isAerial) {
// Don't move while jumping or aerial attack
} else {
// Normal movement - maintain distance from hero
if (distance > 300) {
// Move closer
if (distance > 0) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
} else if (distance < 150) {
// Move away
if (distance > 0) {
self.x -= dx / distance * self.speed;
self.y -= dy / distance * self.speed;
}
}
}
};
return self;
});
var BossBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('bossBullet', {
anchorX: 0.5,
anchorY: 0.5
});
bulletGraphics.scaleX = 1.5; // Scale for appropriate size
bulletGraphics.scaleY = 1.5; // Scale for appropriate size
// Add glowing effect to boss bullets
var glowGraphics = self.attachAsset('bossBullet', {
anchorX: 0.5,
anchorY: 0.5
});
glowGraphics.tint = 0xFF6600; // Orange glow
glowGraphics.alpha = 0.4;
glowGraphics.scaleX = 2;
glowGraphics.scaleY = 2;
// Pulsing glow animation
tween(glowGraphics, {
scaleX: 2.5,
scaleY: 2.5,
alpha: 0.2
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(glowGraphics, {
scaleX: 2,
scaleY: 2,
alpha: 0.4
}, {
duration: 500,
easing: tween.easeInOut
});
}
});
self.speed = 6;
self.damage = 50;
// Boss bullet hitbox properties
self.width = 150; // Boss bullet visual width (100 * 1.5 scale)
self.height = 150; // Boss bullet visual height (100 * 1.5 scale)
self.targetX = 0;
self.targetY = 0;
self.directionX = 0;
self.directionY = 0;
self.setTarget = function (x, y) {
self.targetX = x;
self.targetY = y;
var dx = x - self.x;
var dy = y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
self.directionX = dx / distance;
self.directionY = dy / distance;
}
// Rotate bullet to face direction
bulletGraphics.rotation = Math.atan2(dy, dx) + Math.PI / 2;
};
self.update = function () {
self.x += self.directionX * self.speed;
self.y += self.directionY * self.speed;
// Rotate the boss bullet for visual effect
self.rotation += 0.1;
// Remove bullet if it goes off screen
if (self.x < -50 || self.x > 8242 || self.y < -50 || self.y > 10978) {
self.destroy();
for (var i = bossBullets.length - 1; i >= 0; i--) {
if (bossBullets[i] === self) {
bossBullets.splice(i, 1);
break;
}
}
}
};
return self;
});
var Bullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = Bullet.prototype.baseSpeed || 8;
self.damage = 25;
self.targetX = 0;
self.targetY = 0;
self.directionX = 0;
self.directionY = 0;
self.setTarget = function (x, y) {
self.targetX = x;
self.targetY = y;
var dx = x - self.x;
var dy = y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
self.directionX = dx / distance;
self.directionY = dy / distance;
}
// Rotate bullet to face direction
bulletGraphics.rotation = Math.atan2(dy, dx) + Math.PI / 2;
};
self.update = function () {
self.x += self.directionX * self.speed;
self.y += self.directionY * self.speed;
// Remove bullet if it goes off screen
if (self.x < -50 || self.x > 8242 || self.y < -50 || self.y > 10978) {
self.destroy();
for (var i = bullets.length - 1; i >= 0; i--) {
if (bullets[i] === self) {
bullets.splice(i, 1);
break;
}
}
}
};
return self;
});
var CoinPickup = Container.expand(function () {
var self = Container.call(this);
var coinGraphics = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
coinGraphics.scaleX = 0.8;
coinGraphics.scaleY = 0.8;
// Add glowing effect
var glowGraphics = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
glowGraphics.tint = 0xFFF700; // Bright yellow glow
glowGraphics.alpha = 0.3;
glowGraphics.scaleX = 1.1;
glowGraphics.scaleY = 1.1;
// Add pulsing animation
tween(coinGraphics, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 600,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(coinGraphics, {
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 600,
easing: tween.easeInOut
});
}
});
// Add continuous rotation animation
tween(coinGraphics, {
rotation: Math.PI * 2
}, {
duration: 2000,
easing: tween.linear,
onFinish: function onFinish() {
coinGraphics.rotation = 0;
// Restart rotation
tween(coinGraphics, {
rotation: Math.PI * 2
}, {
duration: 2000,
easing: tween.linear
});
}
});
self.coinValue = 5;
self.moveSpeed = 3;
self.attractRange = 120;
self.update = function () {
// Move toward hero if within attract range
var dx = hero.x - self.x;
var dy = hero.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < self.attractRange) {
if (distance > 0) {
self.x += dx / distance * self.moveSpeed;
self.y += dy / distance * self.moveSpeed;
}
}
// Check if collected by hero
if (distance < 30) {
// Give coins to player
var currentCoins = storage.coins || 0;
storage.coins = currentCoins + self.coinValue;
updateCoinsDisplay();
LK.getSound('xpCollect').play();
LK.effects.flashObject(hero, 0xFFD700, 300); // Gold flash
// Remove from coins array
for (var i = coinPickups.length - 1; i >= 0; i--) {
if (coinPickups[i] === self) {
coinPickups.splice(i, 1);
break;
}
}
self.destroy();
}
};
return self;
});
var FastEnemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('fastEnemy', {
anchorX: 0.5,
anchorY: 0.5
});
// Weapon graphics removed
self.health = 15;
self.maxHealth = 15;
self.damage = 10;
self.speed = 3;
self.scoreValue = 15;
// Enemy hitbox properties
self.width = 150; // Enemy visual width
self.height = 150; // Enemy visual height
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xFFFFFF, 200);
if (self.health <= 0) {
// Create multiple explosion visual effects with different colors and timings
LK.effects.flashObject(self, 0xFF4500, 400); // Red-orange flash
LK.effects.flashScreen(0xFF8C00, 150); // Brief orange screen flash
// Add scaling explosion effect
tween(self, {
scaleX: 2.0,
scaleY: 2.0,
alpha: 0.3
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 0.1,
scaleY: 0.1,
alpha: 0
}, {
duration: 100,
easing: tween.easeIn
});
}
});
// Deal explosion damage to nearby enemies (but prevent chain explosions)
for (var j = 0; j < enemies.length; j++) {
var otherEnemy = enemies[j];
if (otherEnemy !== self) {
var explodeDx = otherEnemy.x - self.x;
var explodeDy = otherEnemy.y - self.y;
var explodeDistance = Math.sqrt(explodeDx * explodeDx + explodeDy * explodeDy);
// Damage enemies within 150 pixel explosion radius
if (explodeDistance < 150) {
// Prevent chain explosions by directly reducing health instead of calling takeDamage
otherEnemy.health -= 25;
if (otherEnemy.health <= 0) {
otherEnemy.health = 0;
// Manually trigger death without explosion effects for other FastEnemies
if (otherEnemy instanceof FastEnemy) {
// Simple death without explosion to prevent recursion
var xpOrb = new XPOrb();
xpOrb.x = otherEnemy.x;
xpOrb.y = otherEnemy.y;
xpOrbs.push(xpOrb);
game.addChild(xpOrb);
otherEnemy.destroy();
LK.setScore(LK.getScore() + otherEnemy.scoreValue);
scoreTxt.setText(LK.getScore());
for (var k = enemies.length - 1; k >= 0; k--) {
if (enemies[k] === otherEnemy) {
enemies.splice(k, 1);
break;
}
}
} else {
// For non-FastEnemies, call takeDamage normally to trigger their death effects
otherEnemy.takeDamage(0);
}
} else {
// Flash effect for damaged but alive enemies
LK.effects.flashObject(otherEnemy, 0xFF4500, 200);
}
// Push enemies away from explosion center
if (explodeDistance > 0) {
otherEnemy.x += explodeDx / explodeDistance * 80;
otherEnemy.y += explodeDy / explodeDistance * 80;
}
}
}
}
// Deal explosion damage to hero if in blast radius
var heroDx = hero.x - self.x;
var heroDy = hero.y - self.y;
var heroDistance = Math.sqrt(heroDx * heroDx + heroDy * heroDy);
if (heroDistance < 150) {
hero.takeDamage(20); // Explosion damage to hero
// Add visual feedback for hero being hit by explosion
LK.effects.flashObject(hero, 0xFF4500, 300);
}
// Drop XP orb
var xpOrb = new XPOrb();
xpOrb.x = self.x;
xpOrb.y = self.y;
xpOrbs.push(xpOrb);
game.addChild(xpOrb);
// 50% chance to drop coin
if (Math.random() < 0.5) {
var coin = new CoinPickup();
coin.x = self.x + (Math.random() - 0.5) * 60;
coin.y = self.y + (Math.random() - 0.5) * 60;
coinPickups.push(coin);
game.addChild(coin);
}
self.destroy();
LK.setScore(LK.getScore() + self.scoreValue);
scoreTxt.setText(LK.getScore());
LK.getSound('enemyDestroy').play();
for (var i = enemies.length - 1; i >= 0; i--) {
if (enemies[i] === self) {
enemies.splice(i, 1);
break;
}
}
}
};
// updateWeapon method removed
self.update = function () {
var dx = hero.x - self.x;
var dy = hero.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Weapon update removed
if (distance > 0) {
var newX = self.x + dx / distance * self.speed;
var newY = self.y + dy / distance * self.speed;
// Check collision with other enemies
var collisionFound = false;
for (var i = 0; i < enemies.length; i++) {
var otherEnemy = enemies[i];
if (otherEnemy !== self) {
var otherDx = newX - otherEnemy.x;
var otherDy = newY - otherEnemy.y;
var otherDistance = Math.sqrt(otherDx * otherDx + otherDy * otherDy);
var minDistance = (self.width + otherEnemy.width) / 4; // Collision threshold
if (otherDistance < minDistance) {
collisionFound = true;
// Push enemies apart
if (otherDistance > 0) {
var pushForce = (minDistance - otherDistance) / 2;
var pushX = otherDx / otherDistance * pushForce;
var pushY = otherDy / otherDistance * pushForce;
newX += pushX;
newY += pushY;
otherEnemy.x -= pushX;
otherEnemy.y -= pushY;
}
}
}
}
// Only move if no major collision or after separation
if (!collisionFound || distance > 100) {
self.x = newX;
self.y = newY;
}
}
};
return self;
});
var HealthCrate = Container.expand(function () {
var self = Container.call(this);
var crateGraphics = self.attachAsset('crate', {
anchorX: 0.5,
anchorY: 0.5
});
crateGraphics.scaleX = 0.8;
crateGraphics.scaleY = 0.8;
self.health = 1;
self.takeDamage = function (damage) {
self.health -= damage;
// Shake effect when hit
LK.effects.flashObject(self, 0xFFFFFF, 100);
tween(self, {
rotation: self.rotation + 0.1
}, {
duration: 50,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
rotation: self.rotation - 0.2
}, {
duration: 50,
easing: tween.easeIn,
onFinish: function onFinish() {
tween(self, {
rotation: self.rotation + 0.1
}, {
duration: 50,
easing: tween.easeOut
});
}
});
}
});
if (self.health <= 0) {
var dropChance = Math.random();
if (dropChance < 0.1) {
// 10% chance to drop level up item
var levelPickup = new LevelPickup();
levelPickup.x = self.x;
levelPickup.y = self.y;
levelPickups.push(levelPickup);
game.addChild(levelPickup);
} else if (dropChance < 0.55) {
// 45% chance to drop XP orb
var xpOrb = new XPOrb();
xpOrb.x = self.x;
xpOrb.y = self.y;
xpOrbs.push(xpOrb);
game.addChild(xpOrb);
} else {
// 45% chance to drop health pickup
var healthPickup = new HealthPickup();
healthPickup.x = self.x;
healthPickup.y = self.y;
healthPickups.push(healthPickup);
game.addChild(healthPickup);
}
self.destroy();
LK.getSound('enemyDestroy').play();
for (var i = healthCrates.length - 1; i >= 0; i--) {
if (healthCrates[i] === self) {
healthCrates.splice(i, 1);
break;
}
}
}
};
return self;
});
var HealthPickup = Container.expand(function () {
var self = Container.call(this);
var pickupGraphics = self.attachAsset('healthBar', {
anchorX: 0.5,
anchorY: 0.5
});
pickupGraphics.scaleX = 0.3;
pickupGraphics.scaleY = 0.3;
pickupGraphics.tint = 0xFF0000; // Red color for health
// Add pulsing animation
tween(pickupGraphics, {
scaleX: 0.35,
scaleY: 0.35
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(pickupGraphics, {
scaleX: 0.3,
scaleY: 0.3
}, {
duration: 800,
easing: tween.easeInOut
});
}
});
self.healAmount = 15;
self.update = function () {
// Check if collected by hero
var dx = hero.x - self.x;
var dy = hero.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 40) {
// Heal player
if (hero.health < hero.maxHealth) {
hero.health = Math.min(hero.health + self.healAmount, hero.maxHealth);
updateHealthBar();
LK.getSound('xpCollect').play();
LK.effects.flashObject(hero, 0x00FF00, 300); // Green flash
}
// Remove from healthPickups array
for (var i = healthPickups.length - 1; i >= 0; i--) {
if (healthPickups[i] === self) {
healthPickups.splice(i, 1);
break;
}
}
self.destroy();
}
};
return self;
});
var Hero = Container.expand(function () {
var self = Container.call(this);
var heroGraphics = self.attachAsset('hero', {
anchorX: 0.5,
anchorY: 0.5
});
var weaponGraphics = self.attachAsset('pistolModel', {
anchorX: 0.5,
anchorY: 0.8 // Better anchor point for weapon rotation
});
weaponGraphics.x = 0;
weaponGraphics.y = 0;
// Set initial weapon scale for better visibility
weaponGraphics.scaleX = 1.2;
weaponGraphics.scaleY = 1.2;
self.maxHealth = 100;
self.health = self.maxHealth;
self.attackDamage = 25;
self.isInvulnerable = false;
// Custom hitbox properties
self.hitboxWidth = 80; // Smaller than visual size for better gameplay
self.hitboxHeight = 100; // Adjusted for character proportions
self.hitboxOffsetX = 0; // Center aligned
self.hitboxOffsetY = 0; // Center aligned
self.takeDamage = function (damage) {
if (self.isInvulnerable) return;
self.health -= damage;
if (self.health <= 0) {
self.health = 0;
// Add death visual effects
LK.effects.flashObject(self, 0xFF0000, 1000); // Long red flash
LK.effects.flashScreen(0x8B0000, 800); // Dark red screen flash
// Make hero semi-transparent to show death
tween(self, {
alpha: 0.3,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 500,
easing: tween.easeOut
});
// Change to death state and show death menu
gameState = 'dead';
// Add a small delay before showing death menu for better UX
LK.setTimeout(function () {
createDeathMenu();
}, 500);
return;
}
// Flash red when taking damage
LK.effects.flashObject(self, 0xFF0000, 300);
LK.getSound('playerHit').play();
// Brief invulnerability
self.isInvulnerable = true;
LK.setTimeout(function () {
self.isInvulnerable = false;
}, 500);
};
self.attack = function (enemy) {
enemy.takeDamage(self.attackDamage);
LK.getSound('enemyHit').play();
// Weapon swing animation
tween(weaponGraphics, {
rotation: weaponGraphics.rotation + Math.PI / 3
}, {
duration: 100
});
};
self.updateWeaponGraphics = function () {
// Map weapon types to their corresponding models
var weaponModels = {
pistol: 'pistolModel',
rifle: 'rifleModel',
shotgun: 'shotgunModel',
machinegun: 'machinegunModel',
sniper: 'rifleModel',
// Use rifle model for sniper
laser: 'laserModel',
explosive: 'explosiveModel'
};
// Get the model for current weapon
var newModel = weaponModels[currentWeapon] || 'pistolModel';
// Remove old weapon graphics
if (weaponGraphics) {
self.removeChild(weaponGraphics);
weaponGraphics.destroy();
}
// Create new weapon graphics with proper model
weaponGraphics = self.attachAsset(newModel, {
anchorX: 0.5,
anchorY: 0.8
});
weaponGraphics.x = 0;
weaponGraphics.y = 0;
weaponGraphics.scaleX = 1.2;
weaponGraphics.scaleY = 1.2;
};
self.updateWeapon = function (targetX, targetY) {
// Calculate angle to target
var dx = targetX - self.x;
var dy = targetY - self.y;
var angle = Math.atan2(dy, dx);
weaponGraphics.rotation = angle + Math.PI / 2;
// Position weapon properly with offset based on rotation
var weaponOffset = 30; // Distance from hero center
weaponGraphics.x = Math.cos(angle) * weaponOffset;
weaponGraphics.y = Math.sin(angle) * weaponOffset;
};
self.shoot = function (targetX, targetY) {
var weapon = weaponTypes[currentWeapon];
// Pre-calculate common values to reduce calculations
var weaponAngle = weaponGraphics.rotation - Math.PI / 2;
var weaponTipOffset = 45; // Distance from hero center to weapon tip
var bulletStartX = self.x + Math.cos(weaponAngle) * weaponTipOffset;
var bulletStartY = self.y + Math.sin(weaponAngle) * weaponTipOffset;
if (currentWeapon === 'shotgun') {
// Ultra-optimized shotgun: pre-calculated spread directions
var bulletCount = 3; // Keep 3 bullets for balance
// Pre-calculated spread directions to avoid trigonometric calculations
var spreadDirections = [{
dx: -0.196,
dy: 0.981
},
// Left spread (~-11.3 degrees)
{
dx: 0,
dy: 1
},
// Center (straight)
{
dx: 0.196,
dy: 0.981
} // Right spread (~11.3 degrees)
];
// Calculate base direction once
var baseDx = targetX - bulletStartX;
var baseDy = targetY - bulletStartY;
var baseDistance = Math.sqrt(baseDx * baseDx + baseDy * baseDy);
if (baseDistance > 0) {
// Normalize base direction
baseDx /= baseDistance;
baseDy /= baseDistance;
for (var i = 0; i < bulletCount; i++) {
var bullet = new Bullet();
bullet.x = bulletStartX;
bullet.y = bulletStartY;
bullet.damage = weapon.damage;
bullet.speed = weapon.bulletSpeed;
// Apply pre-calculated spread using simple rotation
var spread = spreadDirections[i];
var finalDx = baseDx * spread.dy + baseDy * spread.dx;
var finalDy = baseDy * spread.dy - baseDx * spread.dx;
// Set target at fixed distance
bullet.setTarget(bulletStartX + finalDx * 300, bulletStartY + finalDy * 300);
bullets.push(bullet);
game.addChild(bullet);
}
} else {
// Fallback for zero distance
for (var j = 0; j < bulletCount; j++) {
var bullet = new Bullet();
bullet.x = bulletStartX;
bullet.y = bulletStartY;
bullet.damage = weapon.damage;
bullet.speed = weapon.bulletSpeed;
bullet.setTarget(targetX, targetY);
bullets.push(bullet);
game.addChild(bullet);
}
}
} else {
// Single bullet for other weapons
var bullet = new Bullet();
bullet.x = bulletStartX;
bullet.y = bulletStartY;
bullet.damage = weapon.damage;
bullet.speed = weapon.bulletSpeed;
bullet.setTarget(targetX, targetY);
bullets.push(bullet);
game.addChild(bullet);
}
LK.getSound('weaponShoot').play();
// Weapon recoil animation - store original position
var originalWeaponY = weaponGraphics.y;
tween(weaponGraphics, {
y: originalWeaponY + 5
}, {
duration: 50,
onComplete: function onComplete() {
tween(weaponGraphics, {
y: originalWeaponY
}, {
duration: 50
});
}
});
};
self.isWalking = false;
self.moveSpeed = 4;
self.analogMove = function (deltaX, deltaY) {
// Analog movement with wall collision detection
var newX = self.x + deltaX * self.moveSpeed;
var newY = self.y + deltaY * self.moveSpeed;
// Check wall collisions - map boundaries
var mapWidth = 8192;
var mapHeight = 10928;
var wallThickness = 100;
// Prevent going through walls
if (newX < wallThickness + self.hitboxWidth / 2) {
newX = wallThickness + self.hitboxWidth / 2;
}
if (newX > mapWidth - wallThickness - self.hitboxWidth / 2) {
newX = mapWidth - wallThickness - self.hitboxWidth / 2;
}
if (newY < wallThickness + self.hitboxHeight / 2) {
newY = wallThickness + self.hitboxHeight / 2;
}
if (newY > mapHeight - wallThickness - self.hitboxHeight / 2) {
newY = mapHeight - wallThickness - self.hitboxHeight / 2;
}
// Check collision with enemies
var collisionFound = false;
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
var enemyDx = newX - enemy.x;
var enemyDy = newY - enemy.y;
var enemyDistance = Math.sqrt(enemyDx * enemyDx + enemyDy * enemyDy);
var minDistance = (self.hitboxWidth + enemy.width) / 2 + 20; // Add buffer
if (enemyDistance < minDistance) {
collisionFound = true;
// Push hero away from enemy
if (enemyDistance > 0) {
var pushForce = minDistance - enemyDistance;
var pushX = enemyDx / enemyDistance * pushForce;
var pushY = enemyDy / enemyDistance * pushForce;
newX += pushX;
newY += pushY;
}
}
}
// Apply movement only if safe or after collision resolution
self.x = newX;
self.y = newY;
};
self.walkTo = function (targetX, targetY) {
// Don't start new walk if already walking
if (self.isWalking) {
tween.stop(self, {
x: true,
y: true
});
}
self.isWalking = true;
// Check wall collisions and clamp target position
var mapWidth = 8192;
var mapHeight = 10928;
var wallThickness = 100;
// Clamp target position within map boundaries
if (targetX < wallThickness + self.hitboxWidth / 2) {
targetX = wallThickness + self.hitboxWidth / 2;
}
if (targetX > mapWidth - wallThickness - self.hitboxWidth / 2) {
targetX = mapWidth - wallThickness - self.hitboxWidth / 2;
}
if (targetY < wallThickness + self.hitboxHeight / 2) {
targetY = wallThickness + self.hitboxHeight / 2;
}
if (targetY > mapHeight - wallThickness - self.hitboxHeight / 2) {
targetY = mapHeight - wallThickness - self.hitboxHeight / 2;
}
// Calculate distance for duration
var dx = targetX - self.x;
var dy = targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var duration = distance * 2; // Adjust speed by changing multiplier
// Walking animation with slight bounce
tween(heroGraphics, {
scaleY: 0.9
}, {
duration: duration / 4,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(heroGraphics, {
scaleY: 1.1
}, {
duration: duration / 4,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(heroGraphics, {
scaleY: 1.0
}, {
duration: duration / 2,
easing: tween.easeOut
});
}
});
}
});
// Check if target position collides with enemies
var safeTargetX = targetX;
var safeTargetY = targetY;
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
var enemyDx = safeTargetX - enemy.x;
var enemyDy = safeTargetY - enemy.y;
var enemyDistance = Math.sqrt(enemyDx * enemyDx + enemyDy * enemyDy);
var minDistance = (self.hitboxWidth + enemy.width) / 2 + 30; // Safety buffer
if (enemyDistance < minDistance && enemyDistance > 0) {
// Move target position away from enemy
var pushDistance = minDistance - enemyDistance;
safeTargetX += enemyDx / enemyDistance * pushDistance;
safeTargetY += enemyDy / enemyDistance * pushDistance;
}
}
// Move to safe target position
tween(self, {
x: safeTargetX,
y: safeTargetY
}, {
duration: duration,
easing: tween.easeOut,
onFinish: function onFinish() {
self.isWalking = false;
}
});
};
// Custom collision check method using hitbox
self.checkCollision = function (other) {
// Calculate hitbox bounds for hero
var heroLeft = self.x - self.hitboxWidth / 2 + self.hitboxOffsetX;
var heroRight = self.x + self.hitboxWidth / 2 + self.hitboxOffsetX;
var heroTop = self.y - self.hitboxHeight / 2 + self.hitboxOffsetY;
var heroBottom = self.y + self.hitboxHeight / 2 + self.hitboxOffsetY;
// Get other object bounds (assuming standard bounds)
var otherLeft = other.x - other.width / 2;
var otherRight = other.x + other.width / 2;
var otherTop = other.y - other.height / 2;
var otherBottom = other.y + other.height / 2;
// Check for overlap
return heroLeft < otherRight && heroRight > otherLeft && heroTop < otherBottom && heroBottom > otherTop;
};
// Debug method to visualize hitbox (can be called for testing)
self.showHitbox = function () {
if (!self.hitboxVisual) {
self.hitboxVisual = LK.getAsset('attackRange', {
anchorX: 0.5,
anchorY: 0.5
});
self.hitboxVisual.width = self.hitboxWidth;
self.hitboxVisual.height = self.hitboxHeight;
self.hitboxVisual.x = self.hitboxOffsetX;
self.hitboxVisual.y = self.hitboxOffsetY;
self.hitboxVisual.alpha = 0.3;
self.hitboxVisual.tint = 0x00FF00;
self.addChild(self.hitboxVisual);
}
};
return self;
});
var LevelPickup = Container.expand(function () {
var self = Container.call(this);
var pickupGraphics = self.attachAsset('levelBar', {
anchorX: 0.5,
anchorY: 0.5
});
pickupGraphics.scaleX = 0.4;
pickupGraphics.scaleY = 0.4;
pickupGraphics.tint = 0xFFD700; // Gold color for level up
// Add glowing effect
var glowGraphics = self.attachAsset('levelBar', {
anchorX: 0.5,
anchorY: 0.5
});
glowGraphics.tint = 0xFFFF00; // Yellow glow
glowGraphics.alpha = 0.3;
glowGraphics.scaleX = 0.5;
glowGraphics.scaleY = 0.5;
// Add pulsing animation
tween(pickupGraphics, {
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 600,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(pickupGraphics, {
scaleX: 0.4,
scaleY: 0.4
}, {
duration: 600,
easing: tween.easeInOut
});
}
});
// Rotating glow effect
tween(glowGraphics, {
rotation: Math.PI * 2
}, {
duration: 2000,
easing: tween.linear,
onFinish: function onFinish() {
tween(glowGraphics, {
rotation: 0
}, {
duration: 2000,
easing: tween.linear
});
}
});
self.update = function () {
// Check if collected by hero
var dx = hero.x - self.x;
var dy = hero.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 40) {
// Level up player
playerLevel++;
currentXP = 0;
xpToNextLevel = playerLevel * 30;
levelText.setText('Level ' + playerLevel);
// Level up effects
LK.effects.flashScreen(0xFFD700, 500);
hero.maxHealth += 3;
hero.health = hero.maxHealth; // Full heal on level up
updateHealthBar();
updateLevelBar();
LK.getSound('xpCollect').play();
LK.effects.flashObject(hero, 0xFFD700, 500); // Gold flash
// Show upgrade selection
showUpgradeSelection();
// Remove from levelPickups array
for (var i = levelPickups.length - 1; i >= 0; i--) {
if (levelPickups[i] === self) {
levelPickups.splice(i, 1);
break;
}
}
self.destroy();
}
};
return self;
});
var Lightning = Container.expand(function () {
var self = Container.call(this);
var lightningGraphics = self.attachAsset('lightningBolt', {
anchorX: 0.5,
anchorY: 0.5
});
// Add glowing effect to lightning bolt
var glowGraphics = self.attachAsset('lightningBolt', {
anchorX: 0.5,
anchorY: 0.5
});
glowGraphics.tint = 0xFFFF00; // Yellow glow
glowGraphics.alpha = 0.5;
glowGraphics.scaleX = 1.3;
glowGraphics.scaleY = 1.3;
self.speed = 7;
self.damage = 30;
// Lightning bolt hitbox properties
self.width = 80; // Lightning visual width
self.height = 200; // Lightning visual height
self.targetX = 0;
self.targetY = 0;
self.directionX = 0;
self.directionY = 0;
self.lifetime = 0;
self.maxLifetime = 90; // 1.5 seconds at 60fps
// Lightning crackling effect
tween(lightningGraphics, {
alpha: 0.3
}, {
duration: 100,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(lightningGraphics, {
alpha: 1.0
}, {
duration: 100,
easing: tween.easeInOut
});
}
});
self.setTarget = function (x, y) {
self.targetX = x;
self.targetY = y;
var dx = x - self.x;
var dy = y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
self.directionX = dx / distance;
self.directionY = dy / distance;
}
// Rotate lightning to face direction
lightningGraphics.rotation = Math.atan2(dy, dx) + Math.PI / 2;
glowGraphics.rotation = Math.atan2(dy, dx) + Math.PI / 2;
};
self.update = function () {
self.x += self.directionX * self.speed;
self.y += self.directionY * self.speed;
self.lifetime++;
// Random flickering effect
if (Math.random() < 0.3) {
lightningGraphics.alpha = Math.random() * 0.5 + 0.5;
}
// Remove lightning after lifetime expires or goes off screen
if (self.lifetime > self.maxLifetime || self.x < -50 || self.x > 8242 || self.y < -50 || self.y > 10978) {
self.destroy();
for (var i = lightningBolts.length - 1; i >= 0; i--) {
if (lightningBolts[i] === self) {
lightningBolts.splice(i, 1);
break;
}
}
}
};
return self;
});
var MapDecoration = Container.expand(function () {
var self = Container.call(this);
self.decorationType = '';
self.setDecoration = function (type) {
self.decorationType = type;
var decorationGraphics;
switch (type) {
case 'tree':
decorationGraphics = self.attachAsset('tree', {
anchorX: 0.5,
anchorY: 1.0
});
decorationGraphics.tint = 0x228B22;
// Add slight random rotation for variety
decorationGraphics.rotation = (Math.random() - 0.5) * 0.3;
break;
case 'grass':
decorationGraphics = self.attachAsset('grass', {
anchorX: 0.5,
anchorY: 0.5
});
decorationGraphics.tint = 0x32CD32;
decorationGraphics.scaleX = 0.8 + Math.random() * 0.4;
decorationGraphics.scaleY = 0.8 + Math.random() * 0.4;
break;
case 'campfire':
decorationGraphics = self.attachAsset('campfire', {
anchorX: 0.5,
anchorY: 0.5
});
decorationGraphics.tint = 0xFF4500;
// Add flickering animation to campfire
tween(decorationGraphics, {
scaleX: 1.1,
scaleY: 1.1,
alpha: 0.8
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(decorationGraphics, {
scaleX: 1.0,
scaleY: 1.0,
alpha: 1.0
}, {
duration: 800,
easing: tween.easeInOut
});
}
});
break;
}
// Make decorations non-interactive and lower layer
self.alpha = 0.7;
};
return self;
});
var StrongEnemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('strongEnemy', {
anchorX: 0.5,
anchorY: 0.5
});
// Weapon graphics removed
self.health = 50;
self.maxHealth = 50;
self.damage = 25;
self.speed = 2;
self.scoreValue = 25;
// Enemy hitbox properties
self.width = 300; // Enemy visual width
self.height = 300; // Enemy visual height
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xFFFFFF, 200);
if (self.health <= 0) {
// Drop XP orb
var xpOrb = new XPOrb();
xpOrb.x = self.x;
xpOrb.y = self.y;
xpOrbs.push(xpOrb);
game.addChild(xpOrb);
// 50% chance to drop coin
if (Math.random() < 0.5) {
var coin = new CoinPickup();
coin.x = self.x + (Math.random() - 0.5) * 60;
coin.y = self.y + (Math.random() - 0.5) * 60;
coinPickups.push(coin);
game.addChild(coin);
}
self.destroy();
LK.setScore(LK.getScore() + self.scoreValue);
scoreTxt.setText(LK.getScore());
LK.getSound('enemyDestroy').play();
for (var i = enemies.length - 1; i >= 0; i--) {
if (enemies[i] === self) {
enemies.splice(i, 1);
break;
}
}
}
};
// updateWeapon method removed
self.update = function () {
var dx = hero.x - self.x;
var dy = hero.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Weapon update removed
if (distance > 0) {
var newX = self.x + dx / distance * self.speed;
var newY = self.y + dy / distance * self.speed;
// Check collision with other enemies
var collisionFound = false;
for (var i = 0; i < enemies.length; i++) {
var otherEnemy = enemies[i];
if (otherEnemy !== self) {
var otherDx = newX - otherEnemy.x;
var otherDy = newY - otherEnemy.y;
var otherDistance = Math.sqrt(otherDx * otherDx + otherDy * otherDy);
var minDistance = (self.width + otherEnemy.width) / 4; // Collision threshold
if (otherDistance < minDistance) {
collisionFound = true;
// Push enemies apart
if (otherDistance > 0) {
var pushForce = (minDistance - otherDistance) / 2;
var pushX = otherDx / otherDistance * pushForce;
var pushY = otherDy / otherDistance * pushForce;
newX += pushX;
newY += pushY;
otherEnemy.x -= pushX;
otherEnemy.y -= pushY;
}
}
}
}
// Only move if no major collision or after separation
if (!collisionFound || distance > 100) {
self.x = newX;
self.y = newY;
}
}
};
return self;
});
var UpgradeOption = Container.expand(function () {
var self = Container.call(this);
// Background for upgrade option - made larger
var bgGraphics = self.attachAsset('levelBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
bgGraphics.scaleX = 3.5;
bgGraphics.scaleY = 4;
bgGraphics.tint = 0x2c3e50;
// Title text - made larger
self.titleText = new Text2('', {
size: 80,
fill: 0xFFD700
});
self.titleText.anchor.set(0.5, 0.5);
self.titleText.y = -100;
self.addChild(self.titleText);
// Description text - made larger
self.descText = new Text2('', {
size: 60,
fill: 0xFFFFFF
});
self.descText.anchor.set(0.5, 0.5);
self.descText.y = 0;
self.addChild(self.descText);
// Upgrade type
self.upgradeType = '';
self.setUpgrade = function (type, title, description) {
self.upgradeType = type;
self.titleText.setText(title);
self.descText.setText(description);
};
// Hover effect
self.down = function (x, y, obj) {
tween(bgGraphics, {
scaleX: 3.8,
scaleY: 4.3
}, {
duration: 100,
easing: tween.easeOut
});
};
self.up = function (x, y, obj) {
tween(bgGraphics, {
scaleX: 3.5,
scaleY: 4
}, {
duration: 100,
easing: tween.easeIn
});
// Apply the upgrade
applyUpgrade(self.upgradeType);
};
return self;
});
var Wizard = Container.expand(function () {
var self = Container.call(this);
var wizardGraphics = self.attachAsset('Wizard', {
anchorX: 0.5,
anchorY: 0.5
});
// Weapon graphics removed
// Add magical aura effect using the wizard asset
var auraGraphics = self.attachAsset('Wizard', {
anchorX: 0.5,
anchorY: 0.5
});
auraGraphics.tint = 0x9370DB; // Purple aura
auraGraphics.alpha = 0.3;
auraGraphics.scaleX = 1.3;
auraGraphics.scaleY = 1.3;
// Add pulsing magical aura animation
tween(auraGraphics, {
scaleX: 1.8,
scaleY: 1.8,
alpha: 0.1
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(auraGraphics, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 0.3
}, {
duration: 1000,
easing: tween.easeInOut
});
}
});
self.health = 60;
self.maxHealth = 60;
self.damage = 20;
self.speed = 1.8;
self.scoreValue = 30;
// Wizard hitbox properties
self.width = 310; // Wizard visual width
self.height = 310; // Wizard visual height
self.lastLightningTime = 0;
self.lightningCooldown = 60; // 1 second at 60fps - much faster attack speed
self.lightningRange = 600;
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xFFFFFF, 200);
if (self.health <= 0) {
// Drop XP orb
var xpOrb = new XPOrb();
xpOrb.x = self.x;
xpOrb.y = self.y;
xpOrbs.push(xpOrb);
game.addChild(xpOrb);
// 50% chance to drop coin
if (Math.random() < 0.5) {
var coin = new CoinPickup();
coin.x = self.x + (Math.random() - 0.5) * 60;
coin.y = self.y + (Math.random() - 0.5) * 60;
coinPickups.push(coin);
game.addChild(coin);
}
self.destroy();
LK.setScore(LK.getScore() + self.scoreValue);
scoreTxt.setText(LK.getScore());
LK.getSound('enemyDestroy').play();
for (var i = enemies.length - 1; i >= 0; i--) {
if (enemies[i] === self) {
enemies.splice(i, 1);
break;
}
}
}
};
self.shootLightning = function () {
// Create lightning bolt
var lightning = new Lightning();
lightning.x = self.x;
lightning.y = self.y;
lightning.setTarget(hero.x, hero.y);
lightningBolts.push(lightning);
game.addChild(lightning);
// Enhanced lightning casting effects
LK.effects.flashObject(self, 0xFFFF00, 300);
LK.effects.flashObject(auraGraphics, 0xFFFFFF, 400);
// Dramatic casting animation - wizard grows larger then returns
tween(wizardGraphics, {
scaleX: 1.5,
scaleY: 1.5,
rotation: wizardGraphics.rotation + Math.PI / 6
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(wizardGraphics, {
scaleX: 1.2,
scaleY: 1.2,
rotation: wizardGraphics.rotation - Math.PI / 6
}, {
duration: 250,
easing: tween.easeIn
});
}
});
// Aura intensifies during casting
tween(auraGraphics, {
scaleX: 2.2,
scaleY: 2.2,
alpha: 0.6
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(auraGraphics, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 0.3
}, {
duration: 300,
easing: tween.easeIn
});
}
});
};
self.update = function () {
var dx = hero.x - self.x;
var dy = hero.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Weapon update removed
// Keep distance and shoot lightning
if (distance < self.lightningRange && distance > 150) {
// Stop moving and prepare to shoot
var currentTime = LK.ticks;
if (currentTime - self.lastLightningTime > self.lightningCooldown) {
self.shootLightning();
self.lastLightningTime = currentTime;
}
} else if (distance > self.lightningRange) {
// Move closer to hero
if (distance > 0) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
} else if (distance < 150) {
// Move away from hero
if (distance > 0) {
self.x -= dx / distance * self.speed;
self.y -= dy / distance * self.speed;
}
}
};
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 = 5;
self.moveSpeed = 2;
self.attractRange = 150;
// Add pulsing animation to make XP orbs more attractive
tween(orbGraphics, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(orbGraphics, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Restart the pulsing animation
tween(orbGraphics, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 800,
easing: tween.easeInOut
});
}
});
}
});
self.update = function () {
// XP orb magnetic attraction to other nearby orbs
for (var o = 0; o < xpOrbs.length; o++) {
var otherOrb = xpOrbs[o];
if (otherOrb !== self) {
var orbDx = otherOrb.x - self.x;
var orbDy = otherOrb.y - self.y;
var orbDistance = Math.sqrt(orbDx * orbDx + orbDy * orbDy);
// Attract to nearby orbs within 80 pixels
if (orbDistance < 80 && orbDistance > 0) {
var attractForce = 0.5;
self.x += orbDx / orbDistance * attractForce;
self.y += orbDy / orbDistance * attractForce;
}
}
}
// Move toward hero if within attract range
var dx = hero.x - self.x;
var dy = hero.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < self.attractRange) {
if (distance > 0) {
self.x += dx / distance * self.moveSpeed;
self.y += dy / distance * self.moveSpeed;
}
}
// Check if collected by hero
if (distance < 30) {
// Give XP to player
currentXP += self.xpValue;
LK.setScore(LK.getScore() + self.xpValue);
scoreTxt.setText(LK.getScore());
LK.getSound('xpCollect').play();
// Remove from xpOrbs array
for (var i = xpOrbs.length - 1; i >= 0; i--) {
if (xpOrbs[i] === self) {
xpOrbs.splice(i, 1);
break;
}
}
self.destroy();
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x228B22
});
/****
* Game Code
****/
// Menu system variables
var gameState = 'menu'; // 'menu', 'playing', 'paused', 'dead', 'weaponSelect'
var menuContainer;
var gameContainer;
var deathMenuContainer;
var weaponSelectContainer;
var waveWeaponSelectContainer;
var isSelectingWeapon = false;
var hero;
var enemies = [];
var bullets = [];
var xpOrbs = [];
var lightningBolts = [];
var bossBullets = [];
var healthCrates = [];
var healthPickups = [];
var levelPickups = [];
var coinPickups = [];
var coinsText;
var shopContainer;
var scoreboardContainer;
var spawnTimer = 0;
var difficultyLevel = 1;
var spawnedChunks = {}; // Track spawned decoration chunks
var scoreTxt;
var healthBar;
var healthBarBg;
var attackIndicator;
var lastShootTime = 0;
var joystickBase;
var joystickKnob;
var isJoystickActive = false;
var joystickStartX = 0;
var joystickStartY = 0;
var joystickRadius = 80;
var movementX = 0;
var movementY = 0;
var healthText;
var levelBar;
var levelBarBg;
var levelText;
var playerLevel = 1;
var currentXP = 0;
var xpToNextLevel = 30;
var currentWave = 1;
var waveStartTime = 0;
var waveDuration = 60000; // 1 minute in milliseconds
var waveEnemyCount = 0;
var baseEnemiesPerWave = 20;
var waveText;
var waveTimer;
var bossSpawned = false;
var bossHealthBarBg;
var bossHealthBar;
var bossHealthText;
var upgradeSelectionContainer;
var isSelectingUpgrade = false;
var availableUpgrades = [{
type: 'health',
title: 'Health Boost',
description: '+20 Max Health'
}, {
type: 'damage',
title: 'Damage Up',
description: '+10 Attack Damage'
}, {
type: 'speed',
title: 'Speed Boost',
description: '+1 Movement Speed'
}, {
type: 'attackSpeed',
title: 'Attack Speed',
description: 'Faster Shooting'
}, {
type: 'bulletSpeed',
title: 'Bullet Speed',
description: 'Faster Bullets'
}, {
type: 'regen',
title: 'Regeneration',
description: 'Heal 1 HP/sec'
}];
// Weapon types
var weaponTypes = {
pistol: {
name: 'Tabanca',
damage: 25,
shootCooldown: 80,
bulletSpeed: 8,
description: 'Standart silah'
},
rifle: {
name: 'Tüfek',
damage: 40,
shootCooldown: 120,
bulletSpeed: 12,
description: 'Yüksek hasar, yavaş atış',
cost: 0
},
shotgun: {
name: 'Pompalı',
damage: 25,
shootCooldown: 100,
bulletSpeed: 6,
description: '3 mermi, yakın mesafe',
cost: 0
},
machinegun: {
name: 'Makineli',
damage: 8,
shootCooldown: 20,
bulletSpeed: 10,
description: 'Çok hızlı atış',
cost: 0
},
sniper: {
name: 'Keskin Nişancı',
damage: 80,
shootCooldown: 180,
bulletSpeed: 15,
description: 'Yüksek hasar, çok yavaş',
cost: 0
},
laser: {
name: 'Lazer Silahı',
damage: 35,
shootCooldown: 40,
bulletSpeed: 20,
description: 'Hızlı ve hassas',
cost: 0
},
explosive: {
name: 'Patlayıcı',
damage: 50,
shootCooldown: 150,
bulletSpeed: 5,
description: 'Alan hasarı verir',
cost: 0
}
};
var currentWeapon = 'pistol';
var lastRegenTime = 0;
var hasRegen = false;
var mapDecorations = [];
function createEntryMenu() {
// Create menu container
menuContainer = new Container();
game.addChild(menuContainer);
// Create menu background
var menuBg = LK.getAsset('wallHorizontal', {
anchorX: 0.5,
anchorY: 0.5
});
menuBg.x = 2048 / 2;
menuBg.y = 2732 / 2;
menuBg.scaleX = 8;
menuBg.scaleY = 8;
menuBg.tint = 0x1a1a2e;
menuBg.alpha = 0.9;
menuContainer.addChild(menuBg);
// Create game title
var gameTitle = new Text2('SAVAŞ ALANINDA', {
size: 120,
fill: 0xFFD700
});
gameTitle.anchor.set(0.5, 0.5);
gameTitle.x = 2048 / 2;
gameTitle.y = 2732 / 2 - 200;
menuContainer.addChild(gameTitle);
// Create subtitle
var gameSubtitle = new Text2('Hayatta Kal!', {
size: 80,
fill: 0xFFFFFF
});
gameSubtitle.anchor.set(0.5, 0.5);
gameSubtitle.x = 2048 / 2;
gameSubtitle.y = 2732 / 2 - 100;
menuContainer.addChild(gameSubtitle);
// Create play button background
var playButtonBg = LK.getAsset('levelBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
playButtonBg.x = 2048 / 2;
playButtonBg.y = 2732 / 2 + 100;
playButtonBg.scaleX = 4;
playButtonBg.scaleY = 3;
playButtonBg.tint = 0x27ae60;
menuContainer.addChild(playButtonBg);
// Create play button text
var playButtonText = new Text2('OYNA', {
size: 90,
fill: 0xFFFFFF
});
playButtonText.anchor.set(0.5, 0.5);
playButtonText.x = 2048 / 2;
playButtonText.y = 2732 / 2 + 100;
menuContainer.addChild(playButtonText);
// Add button interaction
playButtonBg.down = function (x, y, obj) {
// Button press animation
tween(playButtonBg, {
scaleX: 4.2,
scaleY: 3.2
}, {
duration: 100,
easing: tween.easeOut
});
};
playButtonBg.up = function (x, y, obj) {
// Button release animation and start game
tween(playButtonBg, {
scaleX: 4,
scaleY: 3
}, {
duration: 100,
easing: tween.easeIn,
onFinish: function onFinish() {
startGame();
}
});
};
// Create weapon select button background
var weaponButtonBg = LK.getAsset('levelBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
weaponButtonBg.x = 2048 / 2;
weaponButtonBg.y = 2732 / 2 + 200;
weaponButtonBg.scaleX = 4;
weaponButtonBg.scaleY = 3;
weaponButtonBg.tint = 0xe67e22;
menuContainer.addChild(weaponButtonBg);
// Create weapon select button text
var weaponButtonText = new Text2('SİLAH SEÇ', {
size: 70,
fill: 0xFFFFFF
});
weaponButtonText.anchor.set(0.5, 0.5);
weaponButtonText.x = 2048 / 2;
weaponButtonText.y = 2732 / 2 + 200;
menuContainer.addChild(weaponButtonText);
// Create shop button background
var shopButtonBg = LK.getAsset('levelBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
shopButtonBg.x = 2048 / 2;
shopButtonBg.y = 2732 / 2 + 300;
shopButtonBg.scaleX = 4;
shopButtonBg.scaleY = 3;
shopButtonBg.tint = 0x9b59b6;
menuContainer.addChild(shopButtonBg);
// Create shop button text
var shopButtonText = new Text2('DÜKKAN', {
size: 70,
fill: 0xFFFFFF
});
shopButtonText.anchor.set(0.5, 0.5);
shopButtonText.x = 2048 / 2;
shopButtonText.y = 2732 / 2 + 300;
menuContainer.addChild(shopButtonText);
// Create scoreboard button background
var scoreboardButtonBg = LK.getAsset('levelBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
scoreboardButtonBg.x = 2048 / 2;
scoreboardButtonBg.y = 2732 / 2 + 400;
scoreboardButtonBg.scaleX = 4;
scoreboardButtonBg.scaleY = 3;
scoreboardButtonBg.tint = 0x34495e;
menuContainer.addChild(scoreboardButtonBg);
// Create scoreboard button text
var scoreboardButtonText = new Text2('SKOR TABLOSU', {
size: 60,
fill: 0xFFFFFF
});
scoreboardButtonText.anchor.set(0.5, 0.5);
scoreboardButtonText.x = 2048 / 2;
scoreboardButtonText.y = 2732 / 2 + 400;
menuContainer.addChild(scoreboardButtonText);
// Add weapon button interaction
weaponButtonBg.down = function (x, y, obj) {
tween(weaponButtonBg, {
scaleX: 4.2,
scaleY: 3.2
}, {
duration: 100,
easing: tween.easeOut
});
};
weaponButtonBg.up = function (x, y, obj) {
tween(weaponButtonBg, {
scaleX: 4,
scaleY: 3
}, {
duration: 100,
easing: tween.easeIn,
onFinish: function onFinish() {
showWeaponSelect();
}
});
};
// Add shop button interaction
shopButtonBg.down = function (x, y, obj) {
tween(shopButtonBg, {
scaleX: 4.2,
scaleY: 3.2
}, {
duration: 100,
easing: tween.easeOut
});
};
shopButtonBg.up = function (x, y, obj) {
tween(shopButtonBg, {
scaleX: 4,
scaleY: 3
}, {
duration: 100,
easing: tween.easeIn,
onFinish: function onFinish() {
showShop();
}
});
};
// Add scoreboard button interaction
scoreboardButtonBg.down = function (x, y, obj) {
tween(scoreboardButtonBg, {
scaleX: 4.2,
scaleY: 3.2
}, {
duration: 100,
easing: tween.easeOut
});
};
scoreboardButtonBg.up = function (x, y, obj) {
tween(scoreboardButtonBg, {
scaleX: 4,
scaleY: 3
}, {
duration: 100,
easing: tween.easeIn,
onFinish: function onFinish() {
showScoreboard();
}
});
};
// Create decorative elements around menu
for (var i = 0; i < 6; i++) {
var decorElement = LK.getAsset('hero', {
anchorX: 0.5,
anchorY: 0.5
});
var angle = Math.PI * 2 / 6 * i;
var radius = 300;
decorElement.x = 2048 / 2 + Math.cos(angle) * radius;
decorElement.y = 2732 / 2 + Math.sin(angle) * radius;
decorElement.alpha = 0.3;
decorElement.scaleX = 0.8;
decorElement.scaleY = 0.8;
decorElement.tint = 0x3498db;
menuContainer.addChild(decorElement);
// Add rotation animation
tween(decorElement, {
rotation: Math.PI * 2
}, {
duration: 3000 + i * 500,
easing: tween.linear,
onFinish: function onFinish() {
this.rotation = 0;
}
});
}
}
function showWeaponSelect() {
// Hide menu
menuContainer.visible = false;
gameState = 'weaponSelect';
// Create weapon select container
weaponSelectContainer = new Container();
game.addChild(weaponSelectContainer);
// Create background
var selectBg = LK.getAsset('wallHorizontal', {
anchorX: 0.5,
anchorY: 0.5
});
selectBg.x = 2048 / 2;
selectBg.y = 2732 / 2;
selectBg.scaleX = 10;
selectBg.scaleY = 10;
selectBg.tint = 0x2c3e50;
selectBg.alpha = 0.9;
weaponSelectContainer.addChild(selectBg);
// Create title
var selectTitle = new Text2('SİLAH SEÇİMİ', {
size: 120,
fill: 0xFFD700
});
selectTitle.anchor.set(0.5, 0.5);
selectTitle.x = 2048 / 2;
selectTitle.y = 300;
weaponSelectContainer.addChild(selectTitle);
// Create weapon options - only show owned weapons (max 2)
var ownedWeapons = storage.ownedWeapons || ['pistol'];
var weaponIndex = 0;
for (var w = 0; w < ownedWeapons.length; w++) {
var weaponType = ownedWeapons[w];
var weapon = weaponTypes[weaponType];
var weaponY = 600 + weaponIndex * 200;
// Weapon background
var weaponBg = LK.getAsset('levelBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
weaponBg.x = 2048 / 2;
weaponBg.y = weaponY;
weaponBg.scaleX = 5;
weaponBg.scaleY = 2;
weaponBg.tint = currentWeapon === weaponType ? 0x27ae60 : 0x34495e;
weaponSelectContainer.addChild(weaponBg);
// Weapon name
var weaponName = new Text2(weapon.name, {
size: 60,
fill: 0xFFFFFF
});
weaponName.anchor.set(0, 0.5);
weaponName.x = 2048 / 2 - 400;
weaponName.y = weaponY;
weaponSelectContainer.addChild(weaponName);
// Weapon description
var weaponDesc = new Text2(weapon.description, {
size: 40,
fill: 0xBDC3C7
});
weaponDesc.anchor.set(0, 0.5);
weaponDesc.x = 2048 / 2 - 100;
weaponDesc.y = weaponY;
weaponSelectContainer.addChild(weaponDesc);
// Create closure to capture weapon type
(function (type, bg) {
bg.down = function (x, y, obj) {
tween(bg, {
scaleX: 5.2,
scaleY: 2.2
}, {
duration: 100,
easing: tween.easeOut
});
};
bg.up = function (x, y, obj) {
tween(bg, {
scaleX: 5,
scaleY: 2
}, {
duration: 100,
easing: tween.easeIn,
onFinish: function onFinish() {
currentWeapon = type;
hideWeaponSelect();
}
});
};
})(weaponType, weaponBg);
weaponIndex++;
}
// Create back button
var backButtonBg = LK.getAsset('levelBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
backButtonBg.x = 2048 / 2;
backButtonBg.y = 2732 - 200;
backButtonBg.scaleX = 3;
backButtonBg.scaleY = 2;
backButtonBg.tint = 0x95a5a6;
weaponSelectContainer.addChild(backButtonBg);
var backButtonText = new Text2('GERİ', {
size: 60,
fill: 0xFFFFFF
});
backButtonText.anchor.set(0.5, 0.5);
backButtonText.x = 2048 / 2;
backButtonText.y = 2732 - 200;
weaponSelectContainer.addChild(backButtonText);
backButtonBg.down = function (x, y, obj) {
tween(backButtonBg, {
scaleX: 3.2,
scaleY: 2.2
}, {
duration: 100,
easing: tween.easeOut
});
};
backButtonBg.up = function (x, y, obj) {
tween(backButtonBg, {
scaleX: 3,
scaleY: 2
}, {
duration: 100,
easing: tween.easeIn,
onFinish: function onFinish() {
hideWeaponSelect();
}
});
};
}
function hideWeaponSelect() {
weaponSelectContainer.destroy();
weaponSelectContainer = null;
// Update weapon graphics if hero exists
if (hero) {
hero.updateWeaponGraphics();
hero.lastWeapon = currentWeapon;
}
menuContainer.visible = true;
gameState = 'menu';
}
function startGame() {
// Hide menu
menuContainer.visible = false;
// Change game state
gameState = 'playing';
// Initialize game elements
initializeGame();
}
function createDeathMenu() {
// Create death menu container
deathMenuContainer = new Container();
game.addChild(deathMenuContainer);
// Create death menu background
var deathMenuBg = LK.getAsset('wallHorizontal', {
anchorX: 0.5,
anchorY: 0.5
});
deathMenuBg.x = 2048 / 2;
deathMenuBg.y = 2732 / 2;
deathMenuBg.scaleX = 8;
deathMenuBg.scaleY = 8;
deathMenuBg.tint = 0x8B0000; // Dark red background
deathMenuBg.alpha = 0.9;
deathMenuContainer.addChild(deathMenuBg);
// Create death message
var deathTitle = new Text2('ÖLDÜN!', {
size: 150,
fill: 0xFF0000
});
deathTitle.anchor.set(0.5, 0.5);
deathTitle.x = 2048 / 2;
deathTitle.y = 2732 / 2 - 250;
deathMenuContainer.addChild(deathTitle);
// Create final score display
var finalScoreText = new Text2('Final Skor: ' + LK.getScore(), {
size: 80,
fill: 0xFFFFFF
});
finalScoreText.anchor.set(0.5, 0.5);
finalScoreText.x = 2048 / 2;
finalScoreText.y = 2732 / 2 - 150;
deathMenuContainer.addChild(finalScoreText);
// Create wave reached display
var waveReachedText = new Text2('Ulaşılan Dalga: ' + currentWave, {
size: 60,
fill: 0xFFD700
});
waveReachedText.anchor.set(0.5, 0.5);
waveReachedText.x = 2048 / 2;
waveReachedText.y = 2732 / 2 - 80;
deathMenuContainer.addChild(waveReachedText);
// Create restart button background
var restartButtonBg = LK.getAsset('levelBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
restartButtonBg.x = 2048 / 2;
restartButtonBg.y = 2732 / 2 + 50;
restartButtonBg.scaleX = 4;
restartButtonBg.scaleY = 3;
restartButtonBg.tint = 0x27ae60;
deathMenuContainer.addChild(restartButtonBg);
// Create restart button text
var restartButtonText = new Text2('TEKRAR OYNA', {
size: 70,
fill: 0xFFFFFF
});
restartButtonText.anchor.set(0.5, 0.5);
restartButtonText.x = 2048 / 2;
restartButtonText.y = 2732 / 2 + 50;
deathMenuContainer.addChild(restartButtonText);
// Create menu button background
var menuButtonBg = LK.getAsset('levelBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
menuButtonBg.x = 2048 / 2;
menuButtonBg.y = 2732 / 2 + 150;
menuButtonBg.scaleX = 4;
menuButtonBg.scaleY = 3;
menuButtonBg.tint = 0x3498db;
deathMenuContainer.addChild(menuButtonBg);
// Create menu button text
var menuButtonText = new Text2('ANA MENÜ', {
size: 70,
fill: 0xFFFFFF
});
menuButtonText.anchor.set(0.5, 0.5);
menuButtonText.x = 2048 / 2;
menuButtonText.y = 2732 / 2 + 150;
deathMenuContainer.addChild(menuButtonText);
// Add restart button interaction
restartButtonBg.down = function (x, y, obj) {
// Button press animation
tween(restartButtonBg, {
scaleX: 4.2,
scaleY: 3.2
}, {
duration: 100,
easing: tween.easeOut
});
};
restartButtonBg.up = function (x, y, obj) {
// Button release animation and restart game
tween(restartButtonBg, {
scaleX: 4,
scaleY: 3
}, {
duration: 100,
easing: tween.easeIn,
onFinish: function onFinish() {
restartGame();
}
});
};
// Add menu button interaction
menuButtonBg.down = function (x, y, obj) {
// Button press animation
tween(menuButtonBg, {
scaleX: 4.2,
scaleY: 3.2
}, {
duration: 100,
easing: tween.easeOut
});
};
menuButtonBg.up = function (x, y, obj) {
// Button release animation and go to main menu
tween(menuButtonBg, {
scaleX: 4,
scaleY: 3
}, {
duration: 100,
easing: tween.easeIn,
onFinish: function onFinish() {
returnToMainMenu();
}
});
};
}
function initializeGame() {
// Create game container for all game elements
gameContainer = new Container();
game.addChild(gameContainer);
// Initialize all game UI and elements here
initializeGameUI();
initializeHero();
createMapBoundaries();
generateMapDecorations();
}
function createMapBoundaries() {
// Define map boundaries - large but bounded world
var mapWidth = 8192; // 4x screen width
var mapHeight = 10928; // 4x screen height
var wallThickness = 100;
// Create top wall
var topWall = LK.getAsset('wallHorizontal', {
anchorX: 0.5,
anchorY: 0.5
});
topWall.x = mapWidth / 2;
topWall.y = 0;
topWall.scaleX = 2;
topWall.scaleY = 2.5;
topWall.tint = 0x404040;
gameContainer.addChild(topWall);
// Create bottom wall
var bottomWall = LK.getAsset('wallHorizontal', {
anchorX: 0.5,
anchorY: 0.5
});
bottomWall.x = mapWidth / 2;
bottomWall.y = mapHeight;
bottomWall.scaleX = 2;
bottomWall.scaleY = 2.5;
bottomWall.tint = 0x404040;
gameContainer.addChild(bottomWall);
// Create left wall
var leftWall = LK.getAsset('wallVertical', {
anchorX: 0.5,
anchorY: 0.5
});
leftWall.x = 0;
leftWall.y = mapHeight / 2;
leftWall.scaleX = 2.5;
leftWall.scaleY = 1;
leftWall.tint = 0x404040;
gameContainer.addChild(leftWall);
// Create right wall
var rightWall = LK.getAsset('wallVertical', {
anchorX: 0.5,
anchorY: 0.5
});
rightWall.x = mapWidth;
rightWall.y = mapHeight / 2;
rightWall.scaleX = 2.5;
rightWall.scaleY = 1;
rightWall.tint = 0x404040;
gameContainer.addChild(rightWall);
// Place coins at map corners and edges
var coinPositions = [{
x: 200,
y: 200
},
// Top left corner
{
x: mapWidth - 200,
y: 200
},
// Top right corner
{
x: 200,
y: mapHeight - 200
},
// Bottom left corner
{
x: mapWidth - 200,
y: mapHeight - 200
},
// Bottom right corner
{
x: mapWidth / 2,
y: 200
},
// Top center
{
x: mapWidth / 2,
y: mapHeight - 200
},
// Bottom center
{
x: 200,
y: mapHeight / 2
},
// Left center
{
x: mapWidth - 200,
y: mapHeight / 2
} // Right center
];
for (var i = 0; i < coinPositions.length; i++) {
var coin = new CoinPickup();
coin.x = coinPositions[i].x;
coin.y = coinPositions[i].y;
coin.coinValue = 25; // Higher value coins at map edges
coinPickups.push(coin);
gameContainer.addChild(coin);
}
}
function initializeGameUI() {
// Create score display
scoreTxt = new Text2('0', {
size: 80,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Create health bar background
healthBarBg = LK.getAsset('healthBarBg', {
anchorX: 0,
anchorY: 0
});
healthBarBg.x = 150;
healthBarBg.y = 50;
LK.gui.topLeft.addChild(healthBarBg);
// Create health bar
healthBar = LK.getAsset('healthBar', {
anchorX: 0,
anchorY: 0
});
healthBar.x = 150;
healthBar.y = 50;
LK.gui.topLeft.addChild(healthBar);
// Create health text
healthText = new Text2('100/100', {
size: 40,
fill: 0xFFFFFF
});
healthText.anchor.set(0, 0.5);
healthText.x = 370;
healthText.y = 60;
LK.gui.topLeft.addChild(healthText);
// Create level bar background at bottom
levelBarBg = LK.getAsset('levelBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
levelBarBg.x = 2048 / 2;
levelBarBg.y = 2732 - 60;
gameContainer.addChild(levelBarBg);
// Create level bar fill
levelBar = LK.getAsset('levelBar', {
anchorX: 0,
anchorY: 0.5
});
levelBar.x = levelBarBg.x - levelBarBg.width / 2;
levelBar.y = levelBarBg.y;
gameContainer.addChild(levelBar);
// Create level text
levelText = new Text2('Level 1', {
size: 50,
fill: 0xFFFFFF
});
levelText.anchor.set(0.5, 0.5);
levelText.x = levelBarBg.x;
levelText.y = levelBarBg.y - 50;
gameContainer.addChild(levelText);
// Create wave display
waveText = new Text2('Wave 1', {
size: 60,
fill: 0xFFD700
});
waveText.anchor.set(1, 0);
waveText.x = 2048 - 20;
waveText.y = 20;
LK.gui.topRight.addChild(waveText);
// Create wave timer display
waveTimer = new Text2('2:00', {
size: 50,
fill: 0xFFFFFF
});
waveTimer.anchor.set(0.5, 0);
waveTimer.x = 0;
waveTimer.y = 80;
LK.gui.top.addChild(waveTimer);
// Create coins display
coinsText = new Text2('Coins: 0', {
size: 50,
fill: 0xFFD700
});
coinsText.anchor.set(0, 0);
coinsText.x = 20;
coinsText.y = 100;
LK.gui.topLeft.addChild(coinsText);
updateCoinsDisplay();
// Create upgrade selection container
upgradeSelectionContainer = new Container();
upgradeSelectionContainer.visible = false;
LK.gui.center.addChild(upgradeSelectionContainer);
// Create semi-transparent background
var upgradeBg = LK.getAsset('wallHorizontal', {
anchorX: 0.5,
anchorY: 0.5
});
upgradeBg.scaleX = 8;
upgradeBg.scaleY = 8;
upgradeBg.tint = 0x000000;
upgradeBg.alpha = 0.8;
upgradeSelectionContainer.addChild(upgradeBg);
// Create "Choose Upgrade" title
var upgradeTitle = new Text2('Choose Your Upgrade!', {
size: 80,
fill: 0xFFD700
});
upgradeTitle.anchor.set(0.5, 0.5);
upgradeTitle.y = -200;
upgradeSelectionContainer.addChild(upgradeTitle);
// Create boss health bar background
bossHealthBarBg = LK.getAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0
});
bossHealthBarBg.x = 0;
bossHealthBarBg.y = 140;
bossHealthBarBg.visible = false;
bossHealthBarBg.scaleX = 2;
LK.gui.top.addChild(bossHealthBarBg);
// Create boss health bar
bossHealthBar = LK.getAsset('healthBar', {
anchorX: 0.5,
anchorY: 0
});
bossHealthBar.x = 0;
bossHealthBar.y = 140;
bossHealthBar.visible = false;
bossHealthBar.scaleX = 2;
bossHealthBar.tint = 0xFF4444; // Red color for boss health
LK.gui.top.addChild(bossHealthBar);
// Create boss health text
bossHealthText = new Text2('', {
size: 40,
fill: 0xFFFFFF
});
bossHealthText.anchor.set(0.5, 0);
bossHealthText.x = 0;
bossHealthText.y = 180;
bossHealthText.visible = false;
LK.gui.top.addChild(bossHealthText);
}
function initializeHero() {
// Create hero
hero = gameContainer.addChild(new Hero());
hero.x = 4096;
hero.y = 5464;
// Initialize weapon tracking
hero.lastWeapon = currentWeapon;
// Apply purchased upgrades from storage
if (storage.maxHealth) {
hero.maxHealth = storage.maxHealth;
hero.health = hero.maxHealth;
}
if (storage.attackDamage) {
hero.attackDamage = storage.attackDamage;
}
if (storage.moveSpeed) {
hero.moveSpeed = storage.moveSpeed;
}
// Camera following variables
cameraX = 0;
cameraY = 0;
cameraFollowSpeed = 0.1;
cameraSmoothing = true;
// Create attack range indicator (initially hidden)
attackIndicator = LK.getAsset('attackRange', {
anchorX: 0.5,
anchorY: 0.5
});
attackIndicator.alpha = 0.3;
attackIndicator.visible = false;
gameContainer.addChild(attackIndicator);
// Create attack range circle that shows max shooting distance
var attackRangeCircle = LK.getAsset('jumpMarker', {
anchorX: 0.5,
anchorY: 0.5
});
attackRangeCircle.scaleX = 8; // 800 pixel radius = 1600 pixel diameter
attackRangeCircle.scaleY = 8; // jumpMarker is 200x200, so 8x scale = 1600
attackRangeCircle.alpha = 0.2;
attackRangeCircle.tint = 0x00FF00; // Green color for range indicator
gameContainer.addChild(attackRangeCircle);
// Store reference for updating position
hero.attackRangeCircle = attackRangeCircle;
// Create analog joystick base
joystickBase = LK.getAsset('attackRange', {
anchorX: 0.5,
anchorY: 0.5
});
joystickBase.alpha = 0.2;
joystickBase.visible = false;
joystickBase.scaleX = 1.5;
joystickBase.scaleY = 1.5;
gameContainer.addChild(joystickBase);
// Create analog joystick knob
joystickKnob = LK.getAsset('hero', {
anchorX: 0.5,
anchorY: 0.5
});
joystickKnob.alpha = 0.7;
joystickKnob.visible = false;
joystickKnob.scaleX = 0.6;
joystickKnob.scaleY = 0.6;
gameContainer.addChild(joystickKnob);
}
function generateMapDecorations() {
// Define chunk size for decoration spawning (512x512 pixel chunks)
var chunkSize = 512;
var currentChunkX = Math.floor(hero.x / chunkSize);
var currentChunkY = Math.floor(hero.y / chunkSize);
// Check much larger area around hero (7x7 grid for maximum decoration coverage)
for (var chunkOffsetX = -3; chunkOffsetX <= 3; chunkOffsetX++) {
for (var chunkOffsetY = -3; chunkOffsetY <= 3; chunkOffsetY++) {
var chunkX = currentChunkX + chunkOffsetX;
var chunkY = currentChunkY + chunkOffsetY;
var chunkKey = chunkX + ',' + chunkY;
// Skip if this chunk already has decorations
if (spawnedChunks[chunkKey]) {
continue;
}
// Mark chunk as spawned
spawnedChunks[chunkKey] = true;
// Calculate chunk world position
var chunkWorldX = chunkX * chunkSize + chunkSize / 2;
var chunkWorldY = chunkY * chunkSize + chunkSize / 2;
var decorationTypes = ['tree', 'grass', 'campfire'];
// Reduced decoration density for better performance
var decorationStrategies = {
tree: {
count: 3,
// Reduced trees per chunk
minDistance: 30,
maxDistance: 250,
spacing: 80,
heroAvoidDistance: 70
},
// Fewer trees per chunk
grass: {
count: 8,
// Reduced grass per chunk
minDistance: 10,
maxDistance: 250,
spacing: 30,
heroAvoidDistance: 25
},
// Less grass distributed in chunk
campfire: {
count: 2,
// Fewer campfires per chunk
minDistance: 80,
maxDistance: 220,
spacing: 150,
heroAvoidDistance: 50
} // Fewer campfires
};
// Generate decorations for this chunk
for (var type in decorationStrategies) {
var strategy = decorationStrategies[type];
var count = strategy.count;
// Much higher chance restrictions to ensure many more decorations spawn
if (type === 'campfire' && Math.random() > 0.85) continue; // 85% chance for campfire
if (type === 'tree' && Math.random() > 0.95) continue; // 95% chance for trees
for (var i = 0; i < count; i++) {
var decoration = new MapDecoration();
decoration.setDecoration(type);
var validPosition = false;
var attempts = 0;
var maxAttempts = 20; // Reduced attempts per decoration
// Try to find a valid position within this chunk
while (!validPosition && attempts < maxAttempts) {
// Generate random position within chunk bounds
var randomAngle = Math.random() * Math.PI * 2;
var randomDistance = strategy.minDistance + Math.random() * (strategy.maxDistance - strategy.minDistance);
decoration.x = chunkWorldX + Math.cos(randomAngle) * randomDistance;
decoration.y = chunkWorldY + Math.sin(randomAngle) * randomDistance;
// Ensure decoration stays within chunk bounds
decoration.x = Math.max(chunkX * chunkSize, Math.min((chunkX + 1) * chunkSize, decoration.x));
decoration.y = Math.max(chunkY * chunkSize, Math.min((chunkY + 1) * chunkSize, decoration.y));
// Check distance from hero - avoid spawning too close to hero's current position
var heroDistance = Math.sqrt((decoration.x - hero.x) * (decoration.x - hero.x) + (decoration.y - hero.y) * (decoration.y - hero.y));
if (heroDistance < strategy.heroAvoidDistance) {
attempts++;
continue; // Try again if too close to hero
}
// Check for minimum spacing between decorations of same type
var tooClose = false;
for (var j = 0; j < mapDecorations.length; j++) {
var existingDecoration = mapDecorations[j];
if (existingDecoration.decorationType === type) {
var spacingDx = decoration.x - existingDecoration.x;
var spacingDy = decoration.y - existingDecoration.y;
var spacingDistance = Math.sqrt(spacingDx * spacingDx + spacingDy * spacingDy);
if (spacingDistance < strategy.spacing) {
tooClose = true;
break;
}
}
}
if (!tooClose) {
validPosition = true;
}
attempts++;
}
// Only add decoration if we found a valid position
if (validPosition) {
mapDecorations.push(decoration);
gameContainer.addChild(decoration);
}
}
}
}
}
}
// Initialize entry menu on game start
createEntryMenu();
function spawnEnemy() {
// Determine group size with 30% chance for maximum (10 enemies)
var groupSize;
if (Math.random() < 0.3) {
// 30% chance for maximum group size
groupSize = 10;
} else {
// 70% chance for smaller random group size (3-9 enemies)
groupSize = 3 + Math.floor(Math.random() * 7); // Random between 3-9
}
var groupAngle = Math.random() * Math.PI * 2; // Random direction for group
var groupDistance = 500 + Math.random() * 300; // 500-800 pixels from hero
var groupCenterX = hero.x + Math.cos(groupAngle) * groupDistance;
var groupCenterY = hero.y + Math.sin(groupAngle) * groupDistance;
for (var i = 0; i < groupSize; i++) {
var enemyType = Math.random();
var enemy;
if (enemyType < 0.5) {
enemy = new BasicEnemy();
} else if (enemyType < 0.75) {
enemy = new FastEnemy();
} else if (enemyType < 0.95) {
enemy = new StrongEnemy();
} else {
enemy = new Wizard();
}
// Position enemies in a cluster around the group center
var clusterRadius = 150; // Radius of enemy cluster
var clusterAngle = Math.random() * Math.PI * 2;
var clusterDistance = Math.random() * clusterRadius;
enemy.x = groupCenterX + Math.cos(clusterAngle) * clusterDistance;
enemy.y = groupCenterY + Math.sin(clusterAngle) * clusterDistance;
enemies.push(enemy);
game.addChild(enemy);
}
}
function spawnHealthCrate() {
var crate = new HealthCrate();
// Spawn near hero in infinite world
var crateDistance = 200 + Math.random() * 300; // 200-500 pixels from hero
var crateAngle = Math.random() * Math.PI * 2; // Random angle around hero
crate.x = hero.x + Math.cos(crateAngle) * crateDistance;
crate.y = hero.y + Math.sin(crateAngle) * crateDistance;
healthCrates.push(crate);
game.addChild(crate);
}
function updateHealthBar() {
var healthPercent = hero.health / hero.maxHealth;
healthBar.scaleX = healthPercent;
if (healthPercent > 0.5) {
healthBar.tint = 0x4CAF50; // Green
} else if (healthPercent > 0.25) {
healthBar.tint = 0xFFC107; // Yellow
} else {
healthBar.tint = 0xF44336; // Red
}
// Update health text
healthText.setText(Math.ceil(hero.health) + '/' + hero.maxHealth);
}
function updateLevelBar() {
var xpPercent = currentXP / xpToNextLevel;
levelBar.scaleX = xpPercent;
// Check for level up
if (currentXP >= xpToNextLevel) {
playerLevel++;
currentXP = 0;
xpToNextLevel = playerLevel * 30; // Increase XP requirement
levelText.setText('Level ' + playerLevel);
// Level up effects
LK.effects.flashScreen(0xFFD700, 500);
hero.maxHealth += 3;
hero.health = hero.maxHealth; // Full heal on level up
// Show upgrade selection
showUpgradeSelection();
}
}
function showUpgradeSelection() {
isSelectingUpgrade = true;
upgradeSelectionContainer.visible = true;
// Remove any existing upgrade options
for (var i = upgradeSelectionContainer.children.length - 1; i >= 0; i--) {
var child = upgradeSelectionContainer.children[i];
if (child instanceof UpgradeOption) {
child.destroy();
}
}
// Randomly select 3 different upgrades
var selectedUpgrades = [];
var tempUpgrades = availableUpgrades.slice(); // Copy array
for (var j = 0; j < 3 && tempUpgrades.length > 0; j++) {
var randomIndex = Math.floor(Math.random() * tempUpgrades.length);
selectedUpgrades.push(tempUpgrades[randomIndex]);
tempUpgrades.splice(randomIndex, 1);
}
// Create upgrade option buttons - vertical layout
for (var k = 0; k < selectedUpgrades.length; k++) {
var option = new UpgradeOption();
var upgrade = selectedUpgrades[k];
option.setUpgrade(upgrade.type, upgrade.title, upgrade.description);
option.x = 0; // Center horizontally
option.y = (k - 1) * 300; // Position vertically: -300, 0, 300
upgradeSelectionContainer.addChild(option);
}
}
function applyUpgrade(upgradeType) {
// Mark upgrade as applied
for (var i = 0; i < availableUpgrades.length; i++) {
if (availableUpgrades[i].type === upgradeType) {
availableUpgrades[i].applied = true;
break;
}
}
switch (upgradeType) {
case 'health':
hero.maxHealth += 20;
hero.health += 20;
updateHealthBar();
break;
case 'damage':
hero.attackDamage += 10;
break;
case 'speed':
hero.moveSpeed += 1;
break;
case 'attackSpeed':
// Handled in auto-shoot logic
break;
case 'bulletSpeed':
// Increase all future bullet speeds
Bullet.prototype.baseSpeed = 12; // Default is 8
break;
case 'regen':
hasRegen = true;
break;
}
// Hide upgrade selection
isSelectingUpgrade = false;
upgradeSelectionContainer.visible = false;
}
function updateBossHealthBar() {
// Find if there's a boss enemy alive
var currentBoss = null;
for (var i = 0; i < enemies.length; i++) {
if (enemies[i] instanceof Boss) {
currentBoss = enemies[i];
break;
}
}
// Show/hide boss health bar based on boss presence
if (currentBoss) {
bossHealthBarBg.visible = true;
bossHealthBar.visible = true;
bossHealthText.visible = true;
// Update boss health bar
var bossHealthPercent = currentBoss.health / currentBoss.maxHealth;
bossHealthBar.scaleX = bossHealthPercent * 2; // Scale to match background
// Update boss health text
bossHealthText.setText('Boss: ' + Math.ceil(currentBoss.health) + '/' + currentBoss.maxHealth);
} else {
bossHealthBarBg.visible = false;
bossHealthBar.visible = false;
bossHealthText.visible = false;
}
}
function startNewWave() {
// Show weapon selection after wave 1, shop after other waves
if (currentWave === 1) {
showWaveWeaponSelect();
return;
} else if (currentWave > 1) {
showWaveEndShop();
return;
}
currentWave++;
waveStartTime = Date.now();
waveEnemyCount = 0;
bossSpawned = false;
waveText.setText('Wave ' + currentWave);
// Wave start effects
LK.effects.flashScreen(0x00FF00, 800);
// Increase difficulty each wave
difficultyLevel = currentWave;
}
function restartGame() {
// Hide death menu
deathMenuContainer.visible = false;
// Reset all game variables
resetGameVariables();
// Change game state
gameState = 'playing';
// Clean up existing game elements
cleanupGameElements();
// Initialize game again
initializeGame();
}
function returnToMainMenu() {
// Hide death menu
deathMenuContainer.visible = false;
// Clean up existing game elements
cleanupGameElements();
// Reset game variables
resetGameVariables();
// Show main menu
menuContainer.visible = true;
gameState = 'menu';
}
function resetGameVariables() {
// Reset player stats
playerLevel = 1;
currentXP = 0;
xpToNextLevel = 30;
currentWave = 1;
waveStartTime = 0;
waveEnemyCount = 0;
bossSpawned = false;
lastRegenTime = 0;
hasRegen = false;
spawnTimer = 0;
difficultyLevel = 1;
lastShootTime = 0;
isJoystickActive = false;
movementX = 0;
movementY = 0;
isSelectingUpgrade = false;
isSelectingWeapon = false;
// Reset score
LK.setScore(0);
// Reset upgrade availability
for (var i = 0; i < availableUpgrades.length; i++) {
availableUpgrades[i].applied = false;
}
// Reset bullet speed
Bullet.prototype.baseSpeed = 8;
// Reset weapon to default
currentWeapon = 'pistol';
}
function cleanupGameElements() {
// Destroy all existing game elements
if (gameContainer) {
gameContainer.destroy();
gameContainer = null;
}
// Destroy death menu if it exists
if (deathMenuContainer) {
deathMenuContainer.destroy();
deathMenuContainer = null;
}
// Destroy weapon selection menu if it exists
if (waveWeaponSelectContainer) {
waveWeaponSelectContainer.destroy();
waveWeaponSelectContainer = null;
}
// Clear all arrays
enemies = [];
bullets = [];
xpOrbs = [];
lightningBolts = [];
bossBullets = [];
healthCrates = [];
healthPickups = [];
levelPickups = [];
coinPickups = [];
mapDecorations = [];
spawnedChunks = {}; // Reset spawned chunks tracking
}
function updateWaveTimer() {
var currentTime = Date.now();
var timeElapsed = currentTime - waveStartTime;
var timeRemaining = Math.max(0, waveDuration - timeElapsed);
var minutes = Math.floor(timeRemaining / 60000);
var seconds = Math.floor(timeRemaining % 60000 / 1000);
var timeText = minutes + ':' + (seconds < 10 ? '0' : '') + seconds;
waveTimer.setText(timeText);
// Check if wave time is up or all enemies defeated
if (timeRemaining <= 0 || enemies.length === 0 && waveEnemyCount >= 10) {
startNewWave();
}
}
function updateCamera() {
// Calculate target camera position (center hero on screen)
var targetCameraX = -(hero.x - 2048 / 2);
var targetCameraY = -(hero.y - 2732 / 2);
// No camera bounds for infinite world
if (cameraSmoothing) {
// Smooth camera following using interpolation
cameraX += (targetCameraX - cameraX) * cameraFollowSpeed;
cameraY += (targetCameraY - cameraY) * cameraFollowSpeed;
} else {
// Direct camera following
cameraX = targetCameraX;
cameraY = targetCameraY;
}
// Apply camera position to game container
game.x = cameraX;
game.y = cameraY;
// Update level bar position to follow hero
levelBarBg.x = hero.x;
levelBarBg.y = hero.y + 300; // Position below hero
levelBar.x = levelBarBg.x - levelBarBg.width / 2;
levelBar.y = levelBarBg.y;
levelText.x = levelBarBg.x;
levelText.y = levelBarBg.y - 50;
}
function handleMove(x, y, obj) {
// Handle analog joystick movement
if (isJoystickActive) {
var deltaX = x - joystickStartX;
var deltaY = y - joystickStartY;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
// Limit joystick range
if (distance > joystickRadius) {
deltaX = deltaX / distance * joystickRadius;
deltaY = deltaY / distance * joystickRadius;
}
// Update joystick knob position
joystickKnob.x = joystickStartX + deltaX;
joystickKnob.y = joystickStartY + deltaY;
// Calculate movement values (-1 to 1)
movementX = deltaX / joystickRadius;
movementY = deltaY / joystickRadius;
}
}
game.move = handleMove;
game.down = function (x, y, obj) {
// Only process game input when in playing state
if (gameState === 'playing') {
// Make hero walk to touch position
hero.walkTo(x, y);
}
};
game.up = function (x, y, obj) {
// Only process game input when in playing state
if (gameState === 'playing') {
// Deactivate analog joystick
if (isJoystickActive) {
isJoystickActive = false;
joystickBase.visible = false;
joystickKnob.visible = false;
movementX = 0;
movementY = 0;
}
attackIndicator.visible = false;
}
// Allow death menu interactions when dead
else if (gameState === 'dead') {
// Death menu interactions are handled by the menu buttons themselves
// No additional processing needed here
}
};
game.update = function () {
// Only run game logic when in playing state
if (gameState !== 'playing') {
return;
}
// Initialize wave system on first update
if (waveStartTime === 0) {
waveStartTime = Date.now();
}
// Pause game logic during upgrade selection or weapon selection
if (isSelectingUpgrade || isSelectingWeapon) {
return;
}
// Update wave timer
updateWaveTimer();
// Apply regeneration if unlocked
if (hasRegen && hero.health < hero.maxHealth) {
var currentTime = LK.ticks;
if (currentTime - lastRegenTime > 60) {
// 60 ticks = 1 second
hero.health = Math.min(hero.health + 1, hero.maxHealth);
lastRegenTime = currentTime;
updateHealthBar();
}
}
// Process analog movement
if (isJoystickActive && (Math.abs(movementX) > 0.1 || Math.abs(movementY) > 0.1)) {
hero.analogMove(movementX, movementY);
}
spawnTimer++;
// Check if this is a boss wave (every 3rd wave: 3, 6, 9, etc.)
var isBossWave = currentWave % 3 === 0;
// Boss spawning for every 3rd wave
if (isBossWave && !bossSpawned) {
var boss = new Boss();
// Spawn boss near hero in infinite world
var bossDistance = 600 + Math.random() * 200; // 600-800 pixels from hero
var bossAngle = Math.random() * Math.PI * 2; // Random angle around hero
boss.x = hero.x + Math.cos(bossAngle) * bossDistance;
boss.y = hero.y + Math.sin(bossAngle) * bossDistance;
enemies.push(boss);
game.addChild(boss);
bossSpawned = true;
// Boss spawn effects
LK.effects.flashScreen(0xFF0000, 1000);
} else if (!isBossWave) {
// Regular enemy spawning only on non-boss waves - spawn new groups when all enemies are defeated
// Check if all enemies are defeated and we haven't reached the wave limit
if (enemies.length === 0 && waveEnemyCount < 10) {
// Allow up to 10 groups per wave
spawnEnemy(); // This spawns one group of enemies
waveEnemyCount++; // Track number of groups spawned this wave
spawnTimer = 0;
}
}
// Check if weapon changed and update graphics if needed
if (hero.lastWeapon !== currentWeapon) {
hero.updateWeaponGraphics();
hero.lastWeapon = currentWeapon;
}
// Update weapon to point towards nearest enemy
var nearestEnemy = null;
var nearestDistance = Infinity;
for (var j = 0; j < enemies.length; j++) {
var tempEnemy = enemies[j];
var tempDx = hero.x - tempEnemy.x;
var tempDy = hero.y - tempEnemy.y;
var tempDistance = Math.sqrt(tempDx * tempDx + tempDy * tempDy);
if (tempDistance < nearestDistance) {
nearestEnemy = tempEnemy;
nearestDistance = tempDistance;
}
}
if (nearestEnemy) {
hero.updateWeapon(nearestEnemy.x, nearestEnemy.y);
// Auto-shoot while moving - shoot at nearest enemy
var currentTime = LK.ticks;
var weapon = weaponTypes[currentWeapon];
var shootCooldown = weapon.shootCooldown;
// Check if attack speed upgrade was selected
for (var u = 0; u < availableUpgrades.length; u++) {
if (availableUpgrades[u].type === 'attackSpeed' && availableUpgrades[u].applied) {
shootCooldown = Math.floor(shootCooldown * 0.5); // 50% faster shooting
break;
}
}
if (currentTime - lastShootTime > shootCooldown && nearestDistance < 800) {
hero.shoot(nearestEnemy.x, nearestEnemy.y);
lastShootTime = currentTime;
}
}
// Check bullet collisions with enemies
for (var b = bullets.length - 1; b >= 0; b--) {
var bullet = bullets[b];
var bulletHit = false;
for (var e = enemies.length - 1; e >= 0; e--) {
var enemy = enemies[e];
if (bullet.intersects(enemy)) {
// Bullet hits enemy
enemy.takeDamage(bullet.damage);
bullet.destroy();
bullets.splice(b, 1);
bulletHit = true;
break;
}
}
}
// Check lightning bolt collisions with hero
for (var l = lightningBolts.length - 1; l >= 0; l--) {
var lightning = lightningBolts[l];
if (hero.checkCollision(lightning)) {
// Lightning hits hero
hero.takeDamage(lightning.damage);
LK.effects.flashObject(hero, 0xFFFF00, 300);
lightning.destroy();
lightningBolts.splice(l, 1);
}
}
// Check boss bullet collisions with hero
for (var bb = bossBullets.length - 1; bb >= 0; bb--) {
var bossBullet = bossBullets[bb];
if (hero.checkCollision(bossBullet)) {
// Boss bullet hits hero
hero.takeDamage(bossBullet.damage);
LK.effects.flashObject(hero, 0xFF4500, 300);
bossBullet.destroy();
bossBullets.splice(bb, 1);
}
}
// Check collisions and close combat between hero and enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
var dx = hero.x - enemy.x;
var dy = hero.y - enemy.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Auto-attack when very close (melee range)
if (distance < 60 && !enemy.justAttacked) {
hero.attack(enemy);
enemy.justAttacked = true;
// Reset attack flag after short delay
LK.setTimeout(function () {
if (enemy && !enemy.destroyed) {
enemy.justAttacked = false;
}
}, 300);
} else if (hero.checkCollision(enemy) && !enemy.justHitHero) {
// Take damage from collision but don't destroy enemy
hero.takeDamage(enemy.damage);
enemy.justHitHero = true;
// Reset hit flag after short delay to prevent rapid damage
LK.setTimeout(function () {
if (enemy && !enemy.destroyed) {
enemy.justHitHero = false;
}
}, 1000); // 1 second cooldown between hits
}
// Enemies no longer disappear based on distance from hero
// They will persist until killed by the player
}
// Update high score
var currentScore = LK.getScore();
if (currentScore > (storage.highScore || 0)) {
storage.highScore = currentScore;
}
// Update health bar
updateHealthBar();
// Update level bar
updateLevelBar();
// Update boss health bar
updateBossHealthBar();
// Spawn health crates occasionally
if (LK.ticks % 600 === 0) {
// Every 10 seconds
spawnHealthCrate();
}
// Check bullet collisions with health crates
for (var bc = bullets.length - 1; bc >= 0; bc--) {
var bulletCrate = bullets[bc];
var crateHit = false;
for (var hc = healthCrates.length - 1; hc >= 0; hc--) {
var healthCrate = healthCrates[hc];
if (bulletCrate.intersects(healthCrate)) {
// Bullet hits crate
healthCrate.takeDamage(bulletCrate.damage);
bulletCrate.destroy();
bullets.splice(bc, 1);
crateHit = true;
break;
}
}
}
// Check hero melee attacks on crates
for (var cr = healthCrates.length - 1; cr >= 0; cr--) {
var crate = healthCrates[cr];
var crateDx = hero.x - crate.x;
var crateDy = hero.y - crate.y;
var crateDistance = Math.sqrt(crateDx * crateDx + crateDy * crateDy);
// Auto-attack crates when very close
if (crateDistance < 60 && !crate.justAttacked) {
crate.takeDamage(hero.attackDamage);
crate.justAttacked = true;
// Reset attack flag after short delay
LK.setTimeout(function () {
if (crate && !crate.destroyed) {
crate.justAttacked = false;
}
}, 300);
}
}
// Clean up decorations that are too far from hero
for (var d = mapDecorations.length - 1; d >= 0; d--) {
var decoration = mapDecorations[d];
var decorationDistance = Math.sqrt((decoration.x - hero.x) * (decoration.x - hero.x) + (decoration.y - hero.y) * (decoration.y - hero.y));
if (decorationDistance > 3000) {
// Remove decorations more than 3000 pixels from hero
decoration.destroy();
mapDecorations.splice(d, 1);
}
}
// Dynamically generate new decorations as hero moves
if (LK.ticks % 60 === 0) {
// Every 1 second - much more frequent decoration generation
generateMapDecorations();
}
// Update attack range circle position to follow hero
if (hero.attackRangeCircle) {
hero.attackRangeCircle.x = hero.x;
hero.attackRangeCircle.y = hero.y;
}
// Update camera to follow hero
updateCamera();
scoreTxt.setText(LK.getScore());
updateCoinsDisplay();
};
function updateCoinsDisplay() {
var currentCoins = storage.coins || 0;
coinsText.setText('Coins: ' + currentCoins);
}
function showShop() {
// Hide menu
menuContainer.visible = false;
gameState = 'shop';
// Create shop container
shopContainer = new Container();
game.addChild(shopContainer);
// Create background
var shopBg = LK.getAsset('wallHorizontal', {
anchorX: 0.5,
anchorY: 0.5
});
shopBg.x = 2048 / 2;
shopBg.y = 2732 / 2;
shopBg.scaleX = 10;
shopBg.scaleY = 10;
shopBg.tint = 0x2c3e50;
shopBg.alpha = 0.9;
shopContainer.addChild(shopBg);
// Create title
var shopTitle = new Text2('DÜKKAN', {
size: 120,
fill: 0xFFD700
});
shopTitle.anchor.set(0.5, 0.5);
shopTitle.x = 2048 / 2;
shopTitle.y = 300;
shopContainer.addChild(shopTitle);
// Create coins display
var shopCoinsText = new Text2('Coins: ' + (storage.coins || 0), {
size: 80,
fill: 0xFFD700
});
shopCoinsText.anchor.set(0.5, 0.5);
shopCoinsText.x = 2048 / 2;
shopCoinsText.y = 400;
shopContainer.addChild(shopCoinsText);
// Shop items
var shopItems = [{
name: 'Max Health +20',
cost: 0,
type: 'health'
}, {
name: 'Attack +10',
cost: 0,
type: 'damage'
}, {
name: 'Speed +1',
cost: 0,
type: 'speed'
}];
// Create shop item buttons
for (var i = 0; i < shopItems.length; i++) {
var item = shopItems[i];
var itemY = 600 + i * 150;
// Item background
var itemBg = LK.getAsset('levelBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
itemBg.x = 2048 / 2;
itemBg.y = itemY;
itemBg.scaleX = 6;
itemBg.scaleY = 2;
var currentCoins = storage.coins || 0;
var ownedWeapons = storage.ownedWeapons || ['pistol'];
var canPurchase = currentCoins >= item.cost;
itemBg.tint = canPurchase ? 0x27ae60 : 0x7f8c8d;
shopContainer.addChild(itemBg);
// Item name
var itemName = new Text2(item.name, {
size: 60,
fill: 0xFFFFFF
});
itemName.anchor.set(0, 0.5);
itemName.x = 2048 / 2 - 300;
itemName.y = itemY;
shopContainer.addChild(itemName);
// Item cost
var itemCost = new Text2(item.cost + ' Coins', {
size: 50,
fill: 0xFFD700
});
itemCost.anchor.set(1, 0.5);
itemCost.x = 2048 / 2 + 300;
itemCost.y = itemY;
shopContainer.addChild(itemCost);
// Create closure for button interaction
(function (shopItem, bg, nameText, costText) {
bg.down = function (x, y, obj) {
// Only animate if item can be purchased
var currentCoins = storage.coins || 0;
var ownedWeapons = storage.ownedWeapons || ['pistol'];
var canPurchaseNow = true;
if (shopItem.type === 'weapon') {
if (ownedWeapons.indexOf(shopItem.weaponType) !== -1 || ownedWeapons.length >= 2 || currentCoins < shopItem.cost) {
canPurchaseNow = false;
}
} else if (currentCoins < shopItem.cost) {
canPurchaseNow = false;
}
if (canPurchaseNow) {
tween(bg, {
scaleX: 6.2,
scaleY: 2.2
}, {
duration: 100,
easing: tween.easeOut
});
}
};
bg.up = function (x, y, obj) {
tween(bg, {
scaleX: 6,
scaleY: 2
}, {
duration: 100,
easing: tween.easeIn,
onFinish: function onFinish() {
buyItem(shopItem, shopCoinsText, bg, nameText, costText);
}
});
};
})(item, itemBg, itemName, itemCost);
}
// Create back button
var backButtonBg = LK.getAsset('levelBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
backButtonBg.x = 2048 / 2;
backButtonBg.y = 2732 - 200;
backButtonBg.scaleX = 3;
backButtonBg.scaleY = 2;
backButtonBg.tint = 0x95a5a6;
shopContainer.addChild(backButtonBg);
var backButtonText = new Text2('GERİ', {
size: 60,
fill: 0xFFFFFF
});
backButtonText.anchor.set(0.5, 0.5);
backButtonText.x = 2048 / 2;
backButtonText.y = 2732 - 200;
shopContainer.addChild(backButtonText);
backButtonBg.down = function (x, y, obj) {
tween(backButtonBg, {
scaleX: 3.2,
scaleY: 2.2
}, {
duration: 100,
easing: tween.easeOut
});
};
backButtonBg.up = function (x, y, obj) {
tween(backButtonBg, {
scaleX: 3,
scaleY: 2
}, {
duration: 100,
easing: tween.easeIn,
onFinish: function onFinish() {
hideShop();
}
});
};
}
function buyItem(item, coinsText, bg, nameText, costText) {
var currentCoins = storage.coins || 0;
if (currentCoins >= item.cost) {
// Deduct coins
storage.coins = currentCoins - item.cost;
// Apply upgrade based on type
switch (item.type) {
case 'health':
var currentMaxHealth = storage.maxHealth || 100;
storage.maxHealth = currentMaxHealth + 20;
break;
case 'damage':
var currentDamage = storage.attackDamage || 25;
storage.attackDamage = currentDamage + 10;
break;
case 'speed':
var currentSpeed = storage.moveSpeed || 4;
storage.moveSpeed = currentSpeed + 1;
break;
}
// Update display
coinsText.setText('Coins: ' + storage.coins);
// Update button color
bg.tint = storage.coins >= item.cost ? 0x27ae60 : 0x7f8c8d;
// Success effect
LK.effects.flashScreen(0x00FF00, 300);
LK.getSound('xpCollect').play();
} else {
// Not enough coins effect
LK.effects.flashScreen(0xFF0000, 200);
}
}
function hideShop() {
shopContainer.destroy();
shopContainer = null;
menuContainer.visible = true;
gameState = 'menu';
}
function showScoreboard() {
// Hide menu
menuContainer.visible = false;
gameState = 'scoreboard';
// Create scoreboard container
scoreboardContainer = new Container();
game.addChild(scoreboardContainer);
// Create background
var scoreboardBg = LK.getAsset('wallHorizontal', {
anchorX: 0.5,
anchorY: 0.5
});
scoreboardBg.x = 2048 / 2;
scoreboardBg.y = 2732 / 2;
scoreboardBg.scaleX = 10;
scoreboardBg.scaleY = 10;
scoreboardBg.tint = 0x2c3e50;
scoreboardBg.alpha = 0.9;
scoreboardContainer.addChild(scoreboardBg);
// Create title
var scoreboardTitle = new Text2('SKOR TABLOSU', {
size: 120,
fill: 0xFFD700
});
scoreboardTitle.anchor.set(0.5, 0.5);
scoreboardTitle.x = 2048 / 2;
scoreboardTitle.y = 400;
scoreboardContainer.addChild(scoreboardTitle);
// Create high score display
var highScoreText = new Text2('En Yüksek Skor: ' + (storage.highScore || 0), {
size: 80,
fill: 0x00FF00
});
highScoreText.anchor.set(0.5, 0.5);
highScoreText.x = 2048 / 2;
highScoreText.y = 600;
scoreboardContainer.addChild(highScoreText);
// Create total kills display
var totalKillsText = new Text2('Toplam Öldürme: ' + (storage.totalKills || 0), {
size: 70,
fill: 0xFF6B6B
});
totalKillsText.anchor.set(0.5, 0.5);
totalKillsText.x = 2048 / 2;
totalKillsText.y = 750;
scoreboardContainer.addChild(totalKillsText);
// Create current score display
var currentScoreText = new Text2('Şu Anki Skor: ' + LK.getScore(), {
size: 70,
fill: 0xFFFFFF
});
currentScoreText.anchor.set(0.5, 0.5);
currentScoreText.x = 2048 / 2;
currentScoreText.y = 900;
scoreboardContainer.addChild(currentScoreText);
// Create statistics
var coinsEarned = storage.coins || 0;
var statsText = new Text2('Toplam Para: ' + coinsEarned, {
size: 60,
fill: 0xFFD700
});
statsText.anchor.set(0.5, 0.5);
statsText.x = 2048 / 2;
statsText.y = 1050;
scoreboardContainer.addChild(statsText);
// Create back button
var backButtonBg = LK.getAsset('levelBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
backButtonBg.x = 2048 / 2;
backButtonBg.y = 2732 - 200;
backButtonBg.scaleX = 3;
backButtonBg.scaleY = 2;
backButtonBg.tint = 0x95a5a6;
scoreboardContainer.addChild(backButtonBg);
var backButtonText = new Text2('GERİ', {
size: 60,
fill: 0xFFFFFF
});
backButtonText.anchor.set(0.5, 0.5);
backButtonText.x = 2048 / 2;
backButtonText.y = 2732 - 200;
scoreboardContainer.addChild(backButtonText);
backButtonBg.down = function (x, y, obj) {
tween(backButtonBg, {
scaleX: 3.2,
scaleY: 2.2
}, {
duration: 100,
easing: tween.easeOut
});
};
backButtonBg.up = function (x, y, obj) {
tween(backButtonBg, {
scaleX: 3,
scaleY: 2
}, {
duration: 100,
easing: tween.easeIn,
onFinish: function onFinish() {
hideScoreboard();
}
});
};
}
function hideScoreboard() {
scoreboardContainer.destroy();
scoreboardContainer = null;
menuContainer.visible = true;
gameState = 'menu';
}
function showWaveEndShop() {
// Pause game logic during shop
gameState = 'waveShop';
// Create wave shop container
var waveShopContainer = new Container();
gameContainer.addChild(waveShopContainer);
// Create background
var shopBg = LK.getAsset('wallHorizontal', {
anchorX: 0.5,
anchorY: 0.5
});
shopBg.x = 2048 / 2;
shopBg.y = 2732 / 2;
shopBg.scaleX = 10;
shopBg.scaleY = 10;
shopBg.tint = 0x1a1a2e;
shopBg.alpha = 0.95;
waveShopContainer.addChild(shopBg);
// Create title
var shopTitle = new Text2('TUR TAMAMLANDI!', {
size: 100,
fill: 0xFFD700
});
shopTitle.anchor.set(0.5, 0.5);
shopTitle.x = 2048 / 2;
shopTitle.y = 250;
waveShopContainer.addChild(shopTitle);
// Create wave info
var waveInfo = new Text2('Dalga ' + currentWave + ' Bitti', {
size: 70,
fill: 0xFFFFFF
});
waveInfo.anchor.set(0.5, 0.5);
waveInfo.x = 2048 / 2;
waveInfo.y = 350;
waveShopContainer.addChild(waveInfo);
// Create coins display
var shopCoinsText = new Text2('Paralar: ' + (storage.coins || 0), {
size: 60,
fill: 0xFFD700
});
shopCoinsText.anchor.set(0.5, 0.5);
shopCoinsText.x = 2048 / 2;
shopCoinsText.y = 450;
waveShopContainer.addChild(shopCoinsText);
// Shop items for wave end
var waveShopItems = [{
name: 'Maksimum Can +20',
cost: 50,
type: 'health'
}, {
name: 'Saldırı Gücü +10',
cost: 75,
type: 'damage'
}, {
name: 'Hareket Hızı +1',
cost: 100,
type: 'speed'
}, {
name: 'Can Yenileme',
cost: 150,
type: 'regen'
}];
// Create shop item buttons
for (var i = 0; i < waveShopItems.length; i++) {
var item = waveShopItems[i];
var itemY = 600 + i * 120;
// Item background
var itemBg = LK.getAsset('levelBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
itemBg.x = 2048 / 2;
itemBg.y = itemY;
itemBg.scaleX = 5;
itemBg.scaleY = 1.8;
var currentCoins = storage.coins || 0;
itemBg.tint = currentCoins >= item.cost ? 0x27ae60 : 0x7f8c8d;
waveShopContainer.addChild(itemBg);
// Item name
var itemName = new Text2(item.name, {
size: 50,
fill: 0xFFFFFF
});
itemName.anchor.set(0, 0.5);
itemName.x = 2048 / 2 - 250;
itemName.y = itemY;
waveShopContainer.addChild(itemName);
// Item cost
var itemCost = new Text2(item.cost + ' Para', {
size: 45,
fill: 0xFFD700
});
itemCost.anchor.set(1, 0.5);
itemCost.x = 2048 / 2 + 250;
itemCost.y = itemY;
waveShopContainer.addChild(itemCost);
// Create closure for button interaction
(function (shopItem, bg, coinsDisplay) {
bg.down = function (x, y, obj) {
tween(bg, {
scaleX: 5.2,
scaleY: 2.0
}, {
duration: 100,
easing: tween.easeOut
});
};
bg.up = function (x, y, obj) {
tween(bg, {
scaleX: 5,
scaleY: 1.8
}, {
duration: 100,
easing: tween.easeIn,
onFinish: function onFinish() {
buyWaveItem(shopItem, coinsDisplay, bg);
}
});
};
})(item, itemBg, shopCoinsText);
}
// Create market button
var marketButtonBg = LK.getAsset('levelBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
marketButtonBg.x = 2048 / 2 - 200;
marketButtonBg.y = 2732 - 150;
marketButtonBg.scaleX = 3.5;
marketButtonBg.scaleY = 2.5;
marketButtonBg.tint = 0x9b59b6;
waveShopContainer.addChild(marketButtonBg);
var marketButtonText = new Text2('MARKET', {
size: 60,
fill: 0xFFFFFF
});
marketButtonText.anchor.set(0.5, 0.5);
marketButtonText.x = 2048 / 2 - 200;
marketButtonText.y = 2732 - 150;
waveShopContainer.addChild(marketButtonText);
marketButtonBg.down = function (x, y, obj) {
tween(marketButtonBg, {
scaleX: 3.7,
scaleY: 2.7
}, {
duration: 100,
easing: tween.easeOut
});
};
marketButtonBg.up = function (x, y, obj) {
tween(marketButtonBg, {
scaleX: 3.5,
scaleY: 2.5
}, {
duration: 100,
easing: tween.easeIn,
onFinish: function onFinish() {
waveShopContainer.destroy();
showShop();
}
});
};
// Create continue button
var continueButtonBg = LK.getAsset('levelBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
continueButtonBg.x = 2048 / 2 + 200;
continueButtonBg.y = 2732 - 150;
continueButtonBg.scaleX = 3.5;
continueButtonBg.scaleY = 2.5;
continueButtonBg.tint = 0x3498db;
waveShopContainer.addChild(continueButtonBg);
var continueButtonText = new Text2('DEVAM ET', {
size: 60,
fill: 0xFFFFFF
});
continueButtonText.anchor.set(0.5, 0.5);
continueButtonText.x = 2048 / 2 + 200;
continueButtonText.y = 2732 - 150;
waveShopContainer.addChild(continueButtonText);
continueButtonBg.down = function (x, y, obj) {
tween(continueButtonBg, {
scaleX: 3.7,
scaleY: 2.7
}, {
duration: 100,
easing: tween.easeOut
});
};
continueButtonBg.up = function (x, y, obj) {
tween(continueButtonBg, {
scaleX: 3.5,
scaleY: 2.5
}, {
duration: 100,
easing: tween.easeIn,
onFinish: function onFinish() {
// Close shop and continue to next wave
waveShopContainer.destroy();
continueToNextWave();
}
});
};
}
function buyWaveItem(item, coinsText, bg) {
var currentCoins = storage.coins || 0;
if (currentCoins >= item.cost) {
storage.coins = currentCoins - item.cost;
// Apply upgrade based on type
switch (item.type) {
case 'health':
var currentMaxHealth = storage.maxHealth || 100;
storage.maxHealth = currentMaxHealth + 20;
// Also heal current hero if in game
if (hero) {
hero.maxHealth = storage.maxHealth;
hero.health = Math.min(hero.health + 20, hero.maxHealth);
updateHealthBar();
}
break;
case 'damage':
var currentDamage = storage.attackDamage || 25;
storage.attackDamage = currentDamage + 10;
// Also update current hero if in game
if (hero) {
hero.attackDamage = storage.attackDamage;
}
break;
case 'speed':
var currentSpeed = storage.moveSpeed || 4;
storage.moveSpeed = currentSpeed + 1;
// Also update current hero if in game
if (hero) {
hero.moveSpeed = storage.moveSpeed;
}
break;
case 'regen':
hasRegen = true;
break;
}
// Update display
coinsText.setText('Paralar: ' + storage.coins);
updateCoinsDisplay();
// Update button color
bg.tint = storage.coins >= item.cost ? 0x27ae60 : 0x7f8c8d;
// Success effect
LK.effects.flashScreen(0x00FF00, 300);
LK.getSound('xpCollect').play();
} else {
// Not enough coins effect
LK.effects.flashScreen(0xFF0000, 200);
}
}
function showWaveWeaponSelect() {
// Pause game logic during weapon selection
gameState = 'weaponSelect';
isSelectingWeapon = true;
// Create weapon selection container
waveWeaponSelectContainer = new Container();
gameContainer.addChild(waveWeaponSelectContainer);
// Create background
var weaponBg = LK.getAsset('wallHorizontal', {
anchorX: 0.5,
anchorY: 0.5
});
weaponBg.x = 2048 / 2;
weaponBg.y = 2732 / 2;
weaponBg.scaleX = 15;
weaponBg.scaleY = 15;
weaponBg.tint = 0x1a1a2e;
weaponBg.alpha = 0.95;
waveWeaponSelectContainer.addChild(weaponBg);
// Create title
var weaponTitle = new Text2('SİLAH MARKETİ', {
size: 120,
fill: 0xFFD700
});
weaponTitle.anchor.set(0.5, 0.5);
weaponTitle.x = 2048 / 2;
weaponTitle.y = 300;
waveWeaponSelectContainer.addChild(weaponTitle);
// Create subtitle
var weaponSubtitle = new Text2('Silah seç veya satın al!', {
size: 80,
fill: 0xFFFFFF
});
weaponSubtitle.anchor.set(0.5, 0.5);
weaponSubtitle.x = 2048 / 2;
weaponSubtitle.y = 400;
waveWeaponSelectContainer.addChild(weaponSubtitle);
// Create coins display
var weaponCoinsText = new Text2('Paralar: ' + (storage.coins || 0), {
size: 70,
fill: 0xFFD700
});
weaponCoinsText.anchor.set(0.5, 0.5);
weaponCoinsText.x = 2048 / 2;
weaponCoinsText.y = 480;
waveWeaponSelectContainer.addChild(weaponCoinsText);
// Get owned weapons
var ownedWeapons = storage.ownedWeapons || ['pistol'];
var currentCoins = storage.coins || 0;
// Get all available weapons except pistol
var selectedWeapons = [];
for (var weaponKey in weaponTypes) {
if (weaponKey !== 'pistol') {
selectedWeapons.push(weaponKey);
}
}
// Create weapon option buttons - grid layout for 6 weapons
for (var j = 0; j < selectedWeapons.length; j++) {
var weaponKey = selectedWeapons[j];
var weapon = weaponTypes[weaponKey];
var isOwned = ownedWeapons.indexOf(weaponKey) !== -1;
var canAfford = true; // All weapons are now free
var weaponX = 2048 / 2 + (j % 3 - 1) * 600; // 3 weapons per row
var weaponY = 2732 / 2 + 100 + Math.floor(j / 3) * 300; // 2 rows
// Weapon background
var weaponOptionBg = LK.getAsset('levelBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
weaponOptionBg.x = weaponX;
weaponOptionBg.y = weaponY;
weaponOptionBg.scaleX = 4.5;
weaponOptionBg.scaleY = 8;
// Set background color based on status
if (isOwned) {
weaponOptionBg.tint = 0x27ae60; // Green for owned
} else {
weaponOptionBg.tint = 0x3498db; // Blue for available
}
waveWeaponSelectContainer.addChild(weaponOptionBg);
// Weapon name
var weaponNameText = new Text2(weapon.name, {
size: 70,
fill: 0xFFD700
});
weaponNameText.anchor.set(0.5, 0.5);
weaponNameText.x = weaponX;
weaponNameText.y = weaponY - 80;
waveWeaponSelectContainer.addChild(weaponNameText);
// Weapon description
var weaponDescText = new Text2(weapon.description, {
size: 40,
fill: 0xFFFFFF
});
weaponDescText.anchor.set(0.5, 0.5);
weaponDescText.x = weaponX;
weaponDescText.y = weaponY - 20;
waveWeaponSelectContainer.addChild(weaponDescText);
// Weapon stats
var weaponStatsText = new Text2('Hasar: ' + weapon.damage, {
size: 35,
fill: 0xBDC3C7
});
weaponStatsText.anchor.set(0.5, 0.5);
weaponStatsText.x = weaponX;
weaponStatsText.y = weaponY + 20;
waveWeaponSelectContainer.addChild(weaponStatsText);
// Status text (owned or select)
var statusText;
if (isOwned) {
statusText = new Text2('SAHİP OLUNAN\n(Seç)', {
size: 40,
fill: 0x2ecc71
});
} else {
statusText = new Text2('ÜCRETSIZ\n(Seç)', {
size: 40,
fill: 0x2ecc71
});
}
statusText.anchor.set(0.5, 0.5);
statusText.x = weaponX;
statusText.y = weaponY + 80;
waveWeaponSelectContainer.addChild(statusText);
// Create closure to capture weapon key and costs
(function (selectedWeapon, bg, weapon, isOwned, canAfford, coinsDisplay) {
bg.down = function (x, y, obj) {
tween(bg, {
scaleX: 5.8,
scaleY: 10.3
}, {
duration: 100,
easing: tween.easeOut
});
};
bg.up = function (x, y, obj) {
tween(bg, {
scaleX: 5.5,
scaleY: 10
}, {
duration: 100,
easing: tween.easeIn,
onFinish: function onFinish() {
handleWeaponSelection(selectedWeapon, weapon, isOwned, canAfford, coinsDisplay);
}
});
};
})(weaponKey, weaponOptionBg, weapon, isOwned, canAfford, weaponCoinsText);
}
// Create skip button for continuing without selection
var skipButtonBg = LK.getAsset('levelBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
skipButtonBg.x = 2048 / 2;
skipButtonBg.y = 2732 - 200;
skipButtonBg.scaleX = 4;
skipButtonBg.scaleY = 2.5;
skipButtonBg.tint = 0x95a5a6;
waveWeaponSelectContainer.addChild(skipButtonBg);
var skipButtonText = new Text2('DEVAM ET', {
size: 60,
fill: 0xFFFFFF
});
skipButtonText.anchor.set(0.5, 0.5);
skipButtonText.x = 2048 / 2;
skipButtonText.y = 2732 - 200;
waveWeaponSelectContainer.addChild(skipButtonText);
skipButtonBg.down = function (x, y, obj) {
tween(skipButtonBg, {
scaleX: 4.2,
scaleY: 2.7
}, {
duration: 100,
easing: tween.easeOut
});
};
skipButtonBg.up = function (x, y, obj) {
tween(skipButtonBg, {
scaleX: 4,
scaleY: 2.5
}, {
duration: 100,
easing: tween.easeIn,
onFinish: function onFinish() {
// Skip weapon selection and continue
waveWeaponSelectContainer.destroy();
isSelectingWeapon = false;
continueAfterWeaponSelect();
}
});
};
}
function handleWeaponSelection(weaponKey, weapon, isOwned, canAfford, coinsDisplay) {
var ownedWeapons = storage.ownedWeapons || ['pistol'];
if (isOwned) {
// If already owned, just select it
currentWeapon = weaponKey;
// Update weapon graphics immediately
if (hero) {
hero.updateWeaponGraphics();
hero.lastWeapon = currentWeapon;
}
} else {
// Add weapon to owned weapons (all weapons are now free)
if (!storage.ownedWeapons) {
storage.ownedWeapons = ['pistol'];
}
if (storage.ownedWeapons.indexOf(weaponKey) === -1) {
storage.ownedWeapons.push(weaponKey);
}
// Set as current weapon
currentWeapon = weaponKey;
// Update weapon graphics immediately
if (hero) {
hero.updateWeaponGraphics();
hero.lastWeapon = currentWeapon;
}
}
// Success effects
LK.effects.flashScreen(0x00FF00, 500);
LK.getSound('xpCollect').play();
// Close weapon selection menu
waveWeaponSelectContainer.destroy();
isSelectingWeapon = false;
continueAfterWeaponSelect();
}
function selectWeapon(weaponKey) {
// Add selected weapon to owned weapons
if (!storage.ownedWeapons) {
storage.ownedWeapons = ['pistol'];
}
storage.ownedWeapons.push(weaponKey);
// Set as current weapon
currentWeapon = weaponKey;
// Update weapon graphics immediately
if (hero) {
hero.updateWeaponGraphics();
hero.lastWeapon = currentWeapon;
}
// Close weapon selection menu
waveWeaponSelectContainer.destroy();
isSelectingWeapon = false;
// Success effects
LK.effects.flashScreen(0x00FF00, 500);
LK.getSound('xpCollect').play();
// Continue to next wave
continueAfterWeaponSelect();
}
function continueAfterWeaponSelect() {
currentWave++;
waveStartTime = Date.now();
waveEnemyCount = 0;
bossSpawned = false;
waveText.setText('Wave ' + currentWave);
// Wave start effects
LK.effects.flashScreen(0x00FF00, 800);
// Increase difficulty each wave
difficultyLevel = currentWave;
// Resume game
gameState = 'playing';
}
function continueToNextWave() {
currentWave++;
waveStartTime = Date.now();
waveEnemyCount = 0;
bossSpawned = false;
waveText.setText('Wave ' + currentWave);
// Wave start effects
LK.effects.flashScreen(0x00FF00, 800);
// Increase difficulty each wave
difficultyLevel = currentWave;
// Resume game
gameState = 'playing';
} ===================================================================
--- original.js
+++ change.js
@@ -2011,44 +2011,50 @@
name: 'Tüfek',
damage: 40,
shootCooldown: 120,
bulletSpeed: 12,
- description: 'Yüksek hasar, yavaş atış'
+ description: 'Yüksek hasar, yavaş atış',
+ cost: 0
},
shotgun: {
name: 'Pompalı',
damage: 25,
shootCooldown: 100,
bulletSpeed: 6,
- description: '3 mermi, yakın mesafe'
+ description: '3 mermi, yakın mesafe',
+ cost: 0
},
machinegun: {
name: 'Makineli',
damage: 8,
shootCooldown: 20,
bulletSpeed: 10,
- description: 'Çok hızlı atış'
+ description: 'Çok hızlı atış',
+ cost: 0
},
sniper: {
name: 'Keskin Nişancı',
damage: 80,
shootCooldown: 180,
bulletSpeed: 15,
- description: 'Yüksek hasar, çok yavaş'
+ description: 'Yüksek hasar, çok yavaş',
+ cost: 0
},
laser: {
name: 'Lazer Silahı',
damage: 35,
shootCooldown: 40,
bulletSpeed: 20,
- description: 'Hızlı ve hassas'
+ description: 'Hızlı ve hassas',
+ cost: 0
},
explosive: {
name: 'Patlayıcı',
damage: 50,
shootCooldown: 150,
bulletSpeed: 5,
- description: 'Alan hasarı verir'
+ description: 'Alan hasarı verir',
+ cost: 0
}
};
var currentWeapon = 'pistol';
var lastRegenTime = 0;
@@ -2304,128 +2310,86 @@
selectBg.tint = 0x2c3e50;
selectBg.alpha = 0.9;
weaponSelectContainer.addChild(selectBg);
// Create title
- var selectTitle = new Text2('SİLAH SEÇİMİ VE MARKET', {
- size: 100,
+ var selectTitle = new Text2('SİLAH SEÇİMİ', {
+ size: 120,
fill: 0xFFD700
});
selectTitle.anchor.set(0.5, 0.5);
selectTitle.x = 2048 / 2;
- selectTitle.y = 250;
+ selectTitle.y = 300;
weaponSelectContainer.addChild(selectTitle);
- // Create coins display
- var selectCoinsText = new Text2('Paralar: ' + (storage.coins || 0), {
- size: 60,
- fill: 0xFFD700
- });
- selectCoinsText.anchor.set(0.5, 0.5);
- selectCoinsText.x = 2048 / 2;
- selectCoinsText.y = 320;
- weaponSelectContainer.addChild(selectCoinsText);
- // Get owned weapons and current coins
+ // Create weapon options - only show owned weapons (max 2)
var ownedWeapons = storage.ownedWeapons || ['pistol'];
- var currentCoins = storage.coins || 0;
- // Create weapon options - show all weapons
var weaponIndex = 0;
- for (var weaponType in weaponTypes) {
+ for (var w = 0; w < ownedWeapons.length; w++) {
+ var weaponType = ownedWeapons[w];
var weapon = weaponTypes[weaponType];
- var weaponY = 450 + weaponIndex * 180;
- var isOwned = ownedWeapons.indexOf(weaponType) !== -1;
- var isSelected = currentWeapon === weaponType;
+ var weaponY = 600 + weaponIndex * 200;
// Weapon background
var weaponBg = LK.getAsset('levelBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
weaponBg.x = 2048 / 2;
weaponBg.y = weaponY;
- weaponBg.scaleX = 6;
- weaponBg.scaleY = 2.2;
- // Set background color based on status
- if (isSelected) {
- weaponBg.tint = 0x27ae60; // Green for selected
- } else if (isOwned) {
- weaponBg.tint = 0x3498db; // Blue for owned
- } else {
- weaponBg.tint = 0x95a5a6; // Gray for not owned
- }
+ weaponBg.scaleX = 5;
+ weaponBg.scaleY = 2;
+ weaponBg.tint = currentWeapon === weaponType ? 0x27ae60 : 0x34495e;
weaponSelectContainer.addChild(weaponBg);
// Weapon name
var weaponName = new Text2(weapon.name, {
- size: 55,
+ size: 60,
fill: 0xFFFFFF
});
weaponName.anchor.set(0, 0.5);
- weaponName.x = 2048 / 2 - 450;
+ weaponName.x = 2048 / 2 - 400;
weaponName.y = weaponY;
weaponSelectContainer.addChild(weaponName);
// Weapon description
var weaponDesc = new Text2(weapon.description, {
- size: 38,
+ size: 40,
fill: 0xBDC3C7
});
weaponDesc.anchor.set(0, 0.5);
- weaponDesc.x = 2048 / 2 - 150;
+ weaponDesc.x = 2048 / 2 - 100;
weaponDesc.y = weaponY;
weaponSelectContainer.addChild(weaponDesc);
- // Status/price text
- var statusText;
- if (isOwned) {
- if (isSelected) {
- statusText = new Text2('SEÇİLİ', {
- size: 45,
- fill: 0x2ecc71
- });
- } else {
- statusText = new Text2('SEÇ', {
- size: 45,
- fill: 0x3498db
- });
- }
- } else {
- statusText = new Text2('ÜCRETSİZ', {
- size: 45,
- fill: 0xf39c12
- });
- }
- statusText.anchor.set(1, 0.5);
- statusText.x = 2048 / 2 + 450;
- statusText.y = weaponY;
- weaponSelectContainer.addChild(statusText);
// Create closure to capture weapon type
- (function (type, bg, weapon, isOwned, coinsDisplay) {
+ (function (type, bg) {
bg.down = function (x, y, obj) {
tween(bg, {
- scaleX: 6.2,
- scaleY: 2.4
+ scaleX: 5.2,
+ scaleY: 2.2
}, {
duration: 100,
easing: tween.easeOut
});
};
bg.up = function (x, y, obj) {
tween(bg, {
- scaleX: 6,
- scaleY: 2.2
+ scaleX: 5,
+ scaleY: 2
}, {
duration: 100,
easing: tween.easeIn,
onFinish: function onFinish() {
- handleWeaponSelectPurchase(type, weapon, isOwned, coinsDisplay);
+ currentWeapon = type;
+ hideWeaponSelect();
}
});
};
- })(weaponType, weaponBg, weapon, isOwned, selectCoinsText);
+ })(weaponType, weaponBg);
weaponIndex++;
}
// Create back button
var backButtonBg = LK.getAsset('levelBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
backButtonBg.x = 2048 / 2;
- backButtonBg.y = 2732 - 150;
+ backButtonBg.y = 2732 - 200;
backButtonBg.scaleX = 3;
backButtonBg.scaleY = 2;
backButtonBg.tint = 0x95a5a6;
weaponSelectContainer.addChild(backButtonBg);
@@ -2434,9 +2398,9 @@
fill: 0xFFFFFF
});
backButtonText.anchor.set(0.5, 0.5);
backButtonText.x = 2048 / 2;
- backButtonText.y = 2732 - 150;
+ backButtonText.y = 2732 - 200;
weaponSelectContainer.addChild(backButtonText);
backButtonBg.down = function (x, y, obj) {
tween(backButtonBg, {
scaleX: 3.2,
@@ -3659,38 +3623,18 @@
shopContainer.addChild(shopCoinsText);
// Shop items
var shopItems = [{
name: 'Max Health +20',
- cost: 50,
+ cost: 0,
type: 'health'
}, {
name: 'Attack +10',
- cost: 75,
+ cost: 0,
type: 'damage'
}, {
name: 'Speed +1',
- cost: 100,
+ cost: 0,
type: 'speed'
- }, {
- name: 'Makineli Tüfek',
- cost: 200,
- type: 'weapon',
- weaponType: 'machinegun'
- }, {
- name: 'Keskin Nişancı',
- cost: 300,
- type: 'weapon',
- weaponType: 'sniper'
- }, {
- name: 'Lazer Silahı',
- cost: 250,
- type: 'weapon',
- weaponType: 'laser'
- }, {
- name: 'Patlayıcı',
- cost: 350,
- type: 'weapon',
- weaponType: 'explosive'
}];
// Create shop item buttons
for (var i = 0; i < shopItems.length; i++) {
var item = shopItems[i];
@@ -3705,34 +3649,10 @@
itemBg.scaleX = 6;
itemBg.scaleY = 2;
var currentCoins = storage.coins || 0;
var ownedWeapons = storage.ownedWeapons || ['pistol'];
- var canPurchase = true;
- // Check weapon-specific conditions
- if (item.type === 'weapon') {
- // Already owned this weapon
- if (ownedWeapons.indexOf(item.weaponType) !== -1) {
- canPurchase = false;
- itemBg.tint = 0x95a5a6; // Gray for already owned
- }
- // At weapon limit (2 weapons max)
- else if (ownedWeapons.length >= 2) {
- canPurchase = false;
- itemBg.tint = 0x8e44ad; // Purple for weapon limit reached
- }
- // Can purchase weapon (has enough coins)
- else if (currentCoins >= item.cost) {
- canPurchase = true;
- itemBg.tint = 0x27ae60; // Green for available
- } else {
- canPurchase = false;
- itemBg.tint = 0x7f8c8d; // Gray for insufficient coins
- }
- } else {
- // Non-weapon items
- canPurchase = currentCoins >= item.cost;
- itemBg.tint = currentCoins >= item.cost ? 0x27ae60 : 0x7f8c8d;
- }
+ var canPurchase = currentCoins >= item.cost;
+ itemBg.tint = canPurchase ? 0x27ae60 : 0x7f8c8d;
shopContainer.addChild(itemBg);
// Item name
var itemName = new Text2(item.name, {
size: 60,
@@ -3832,27 +3752,9 @@
}
function buyItem(item, coinsText, bg, nameText, costText) {
var currentCoins = storage.coins || 0;
if (currentCoins >= item.cost) {
- // For weapon purchases, validate conditions first before deducting coins
- if (item.type === 'weapon') {
- if (!storage.ownedWeapons) {
- storage.ownedWeapons = ['pistol']; // Start with only pistol
- }
- // Check if weapon is already owned
- if (storage.ownedWeapons.indexOf(item.weaponType) !== -1) {
- // Already owned, show message and don't purchase
- LK.effects.flashScreen(0xFFFF00, 200);
- return;
- }
- // Check weapon limit (maximum 2 weapons)
- if (storage.ownedWeapons.length >= 2) {
- // At weapon limit, show error message
- LK.effects.flashScreen(0xFF0000, 300);
- return;
- }
- }
- // Deduct coins only after all validations pass
+ // Deduct coins
storage.coins = currentCoins - item.cost;
// Apply upgrade based on type
switch (item.type) {
case 'health':
@@ -3866,22 +3768,8 @@
case 'speed':
var currentSpeed = storage.moveSpeed || 4;
storage.moveSpeed = currentSpeed + 1;
break;
- case 'weapon':
- // Add new weapon to inventory (validation already passed above)
- if (!storage.ownedWeapons) {
- storage.ownedWeapons = ['pistol'];
- }
- storage.ownedWeapons.push(item.weaponType);
- // Set as current weapon if player wants
- currentWeapon = item.weaponType;
- // Update weapon graphics if hero exists
- if (hero) {
- hero.updateWeaponGraphics();
- hero.lastWeapon = currentWeapon;
- }
- break;
}
// Update display
coinsText.setText('Coins: ' + storage.coins);
// Update button color
@@ -4315,46 +4203,37 @@
waveWeaponSelectContainer.addChild(weaponCoinsText);
// Get owned weapons
var ownedWeapons = storage.ownedWeapons || ['pistol'];
var currentCoins = storage.coins || 0;
- // Get all available weapons except pistol
- var availableWeapons = [];
+ // Get all available weapons except pistol
+ var selectedWeapons = [];
for (var weaponKey in weaponTypes) {
if (weaponKey !== 'pistol') {
- availableWeapons.push(weaponKey);
+ selectedWeapons.push(weaponKey);
}
}
- // Randomly select 3 weapons from all available weapons
- var selectedWeapons = [];
- var tempWeapons = availableWeapons.slice(); // Copy array
- for (var i = 0; i < 3 && tempWeapons.length > 0; i++) {
- var randomIndex = Math.floor(Math.random() * tempWeapons.length);
- selectedWeapons.push(tempWeapons[randomIndex]);
- tempWeapons.splice(randomIndex, 1);
- }
- // Create weapon option buttons - horizontal layout
+ // Create weapon option buttons - grid layout for 6 weapons
for (var j = 0; j < selectedWeapons.length; j++) {
var weaponKey = selectedWeapons[j];
var weapon = weaponTypes[weaponKey];
var isOwned = ownedWeapons.indexOf(weaponKey) !== -1;
- var canAfford = currentCoins >= (weapon.cost || 0);
- var weaponX = 2048 / 2 + (j - 1) * 600; // Position horizontally
+ var canAfford = true; // All weapons are now free
+ var weaponX = 2048 / 2 + (j % 3 - 1) * 600; // 3 weapons per row
+ var weaponY = 2732 / 2 + 100 + Math.floor(j / 3) * 300; // 2 rows
// Weapon background
var weaponOptionBg = LK.getAsset('levelBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
weaponOptionBg.x = weaponX;
- weaponOptionBg.y = 2732 / 2 + 200;
- weaponOptionBg.scaleX = 5.5;
- weaponOptionBg.scaleY = 10;
+ weaponOptionBg.y = weaponY;
+ weaponOptionBg.scaleX = 4.5;
+ weaponOptionBg.scaleY = 8;
// Set background color based on status
if (isOwned) {
weaponOptionBg.tint = 0x27ae60; // Green for owned
- } else if (weapon.cost && !canAfford) {
- weaponOptionBg.tint = 0x7f8c8d; // Gray for unaffordable
} else {
- weaponOptionBg.tint = 0x3498db; // Blue for purchasable
+ weaponOptionBg.tint = 0x3498db; // Blue for available
}
waveWeaponSelectContainer.addChild(weaponOptionBg);
// Weapon name
var weaponNameText = new Text2(weapon.name, {
@@ -4362,56 +4241,44 @@
fill: 0xFFD700
});
weaponNameText.anchor.set(0.5, 0.5);
weaponNameText.x = weaponX;
- weaponNameText.y = 2732 / 2 + 80;
+ weaponNameText.y = weaponY - 80;
waveWeaponSelectContainer.addChild(weaponNameText);
// Weapon description
var weaponDescText = new Text2(weapon.description, {
- size: 50,
+ size: 40,
fill: 0xFFFFFF
});
weaponDescText.anchor.set(0.5, 0.5);
weaponDescText.x = weaponX;
- weaponDescText.y = 2732 / 2 + 140;
+ weaponDescText.y = weaponY - 20;
waveWeaponSelectContainer.addChild(weaponDescText);
// Weapon stats
- var weaponStatsText = new Text2('Hasar: ' + weapon.damage + '\nAtış Hızı: ' + Math.round(1000 / weapon.shootCooldown), {
- size: 45,
+ var weaponStatsText = new Text2('Hasar: ' + weapon.damage, {
+ size: 35,
fill: 0xBDC3C7
});
weaponStatsText.anchor.set(0.5, 0.5);
weaponStatsText.x = weaponX;
- weaponStatsText.y = 2732 / 2 + 200;
+ weaponStatsText.y = weaponY + 20;
waveWeaponSelectContainer.addChild(weaponStatsText);
- // Status text (owned, cost, or select)
+ // Status text (owned or select)
var statusText;
if (isOwned) {
statusText = new Text2('SAHİP OLUNAN\n(Seç)', {
- size: 50,
+ size: 40,
fill: 0x2ecc71
});
- } else if (weapon.cost) {
- if (canAfford) {
- statusText = new Text2('SATIN AL\n' + weapon.cost + ' Para', {
- size: 50,
- fill: 0xf39c12
- });
- } else {
- statusText = new Text2('YETERSİZ PARA\n' + weapon.cost + ' Para', {
- size: 50,
- fill: 0xe74c3c
- });
- }
} else {
statusText = new Text2('ÜCRETSIZ\n(Seç)', {
- size: 50,
+ size: 40,
fill: 0x2ecc71
});
}
statusText.anchor.set(0.5, 0.5);
statusText.x = weaponX;
- statusText.y = 2732 / 2 + 280;
+ statusText.y = weaponY + 80;
waveWeaponSelectContainer.addChild(statusText);
// Create closure to capture weapon key and costs
(function (selectedWeapon, bg, weapon, isOwned, canAfford, coinsDisplay) {
bg.down = function (x, y, obj) {
@@ -4482,79 +4349,39 @@
};
}
function handleWeaponSelection(weaponKey, weapon, isOwned, canAfford, coinsDisplay) {
var ownedWeapons = storage.ownedWeapons || ['pistol'];
- var currentCoins = storage.coins || 0;
if (isOwned) {
// If already owned, just select it
currentWeapon = weaponKey;
// Update weapon graphics immediately
if (hero) {
hero.updateWeaponGraphics();
hero.lastWeapon = currentWeapon;
}
- // Success effects
- LK.effects.flashScreen(0x00FF00, 500);
- LK.getSound('xpCollect').play();
- // Close weapon selection menu
- waveWeaponSelectContainer.destroy();
- isSelectingWeapon = false;
- continueAfterWeaponSelect();
- } else if (weapon.cost && currentCoins >= weapon.cost) {
- // Purchase the weapon
- storage.coins = currentCoins - weapon.cost;
- // Add to owned weapons if not at limit
- if (ownedWeapons.length < 2) {
- ownedWeapons.push(weaponKey);
- storage.ownedWeapons = ownedWeapons;
- // Set as current weapon
- currentWeapon = weaponKey;
- // Update weapon graphics immediately
- if (hero) {
- hero.updateWeaponGraphics();
- hero.lastWeapon = currentWeapon;
- }
- // Update coins display
- coinsDisplay.setText('Paralar: ' + storage.coins);
- updateCoinsDisplay();
- // Success effects
- LK.effects.flashScreen(0x00FF00, 500);
- LK.getSound('xpCollect').play();
- // Close weapon selection menu
- waveWeaponSelectContainer.destroy();
- isSelectingWeapon = false;
- continueAfterWeaponSelect();
- } else {
- // Weapon limit reached
- LK.effects.flashScreen(0xFF0000, 300);
+ } else {
+ // Add weapon to owned weapons (all weapons are now free)
+ if (!storage.ownedWeapons) {
+ storage.ownedWeapons = ['pistol'];
}
- } else if (!weapon.cost) {
- // Free weapon (like basic weapons)
- if (ownedWeapons.length < 2) {
- ownedWeapons.push(weaponKey);
- storage.ownedWeapons = ownedWeapons;
- // Set as current weapon
- currentWeapon = weaponKey;
- // Update weapon graphics immediately
- if (hero) {
- hero.updateWeaponGraphics();
- hero.lastWeapon = currentWeapon;
- }
- // Success effects
- LK.effects.flashScreen(0x00FF00, 500);
- LK.getSound('xpCollect').play();
- // Close weapon selection menu
- waveWeaponSelectContainer.destroy();
- isSelectingWeapon = false;
- continueAfterWeaponSelect();
- } else {
- // Weapon limit reached
- LK.effects.flashScreen(0xFF0000, 300);
+ if (storage.ownedWeapons.indexOf(weaponKey) === -1) {
+ storage.ownedWeapons.push(weaponKey);
}
- } else {
- // Cannot afford
- LK.effects.flashScreen(0xFF0000, 200);
+ // Set as current weapon
+ currentWeapon = weaponKey;
+ // Update weapon graphics immediately
+ if (hero) {
+ hero.updateWeaponGraphics();
+ hero.lastWeapon = currentWeapon;
+ }
}
+ // Success effects
+ LK.effects.flashScreen(0x00FF00, 500);
+ LK.getSound('xpCollect').play();
+ // Close weapon selection menu
+ waveWeaponSelectContainer.destroy();
+ isSelectingWeapon = false;
+ continueAfterWeaponSelect();
}
function selectWeapon(weaponKey) {
// Add selected weapon to owned weapons
if (!storage.ownedWeapons) {
@@ -4601,44 +4428,5 @@
// Increase difficulty each wave
difficultyLevel = currentWave;
// Resume game
gameState = 'playing';
-}
-function handleWeaponSelectPurchase(weaponType, weapon, isOwned, coinsDisplay) {
- if (isOwned) {
- // If already owned, just select it
- currentWeapon = weaponType;
- // Update weapon graphics if hero exists
- if (hero) {
- hero.updateWeaponGraphics();
- hero.lastWeapon = currentWeapon;
- }
- // Success effects
- LK.effects.flashScreen(0x00FF00, 300);
- LK.getSound('xpCollect').play();
- hideWeaponSelect();
- } else {
- // Purchase the weapon (all weapons are now free)
- if (!storage.ownedWeapons) {
- storage.ownedWeapons = ['pistol'];
- }
- // Add to owned weapons
- storage.ownedWeapons.push(weaponType);
- // Set as current weapon
- currentWeapon = weaponType;
- // Update weapon graphics if hero exists
- if (hero) {
- hero.updateWeaponGraphics();
- hero.lastWeapon = currentWeapon;
- }
- // Update coins display
- updateCoinsDisplay();
- // Success effects
- LK.effects.flashScreen(0x00FF00, 500);
- LK.getSound('xpCollect').play();
- // Refresh the weapon select menu to show updated status
- hideWeaponSelect();
- LK.setTimeout(function () {
- showWeaponSelect();
- }, 100);
- }
}
\ No newline at end of file
Ucan bomba. In-Game asset. 2d. High contrast. No shadows
Qanli iskelet. In-Game asset. 2d. High contrast. No shadows
Beyaz zirhli sovalye. In-Game asset. 2d. High contrast. No shadows
Iskeleten Elektirik buycusu. In-Game asset. 2d. High contrast. No shadows
Wiking boss. In-Game asset. 2d. High contrast. No shadows
Mavi tatli kucuk slime gozleri parildasin. In-Game asset. 2d. High contrast. No shadows
Yesil top halinde tukuruk. In-Game asset. 2d. High contrast. No shadows
Simsek topu. In-Game asset. 2d. High contrast. No shadows
Sandik. In-Game asset. 2d. High contrast. No shadows
Ağac. In-Game asset. 2d. High contrast. No shadows
Cim yesilik. In-Game asset. 2d. High contrast. No shadows
Kamp atesi. In-Game asset. 2d. High contrast. No shadows
Madeni para. In-Game asset. 2d. High contrast. No shadows
Bullet. In-Game asset. 2d. High contrast. No shadows
Lasergun. In-Game asset. 2d. High contrast. No shadows