User prompt
Please fix the bug: 'storage.getItem is not a function' in or related to this line: 'var bestSurvivalTime = parseInt(storage.getItem('bestTime') || "0", 10);' Line Number: 1503
User prompt
Please fix the bug: 'storage.get is not a function' in or related to this line: 'var bestSurvivalTime = parseInt(storage.get('bestTime') || "0", 10);' Line Number: 1503
User prompt
Please fix the bug: 'storage.getItem is not a function' in or related to this line: 'var bestSurvivalTime = parseInt(storage.getItem('bestTime') || "0", 10);' Line Number: 1503
User prompt
Please fix the bug: 'storage.get is not a function' in or related to this line: 'var bestSurvivalTime = parseInt(storage.get('bestTime') || "0", 10);' Line Number: 1503
User prompt
Please fix the bug: 'storage.getItem is not a function' in or related to this line: 'var bestSurvivalTime = parseInt(storage.getItem('bestTime') || "0", 10);' Line Number: 1503
User prompt
Please fix the bug: 'storage.get is not a function' in or related to this line: 'var bestSurvivalTime = storage.get('bestTime') || 0;' Line Number: 1503
User prompt
I want all the part. Implement it!
User prompt
It would be enough if it was in the joystick area, not in the knob area! A circular area!
User prompt
I think you messed up the code really bad. I can't move using the joystick at all right now. None of your solutions worked. You need to think better.
User prompt
I can't move at all using the joystick right now! It's not fixed!
User prompt
It's not fixed! I can't control the movement right now! I can't touch the joystick or the knob!
User prompt
Now even if I click inside the joystick area I cannot control it in any way.
User prompt
Right now I can control the knob by pressing the outside of the joystick. I don't want that to happen. I need to be able to control the knob only from the joystick.
User prompt
Right now, when I try to hold the joystick knob, I can't control it by holding it from the exact place where I click (press) and turning it, the knob slides directly down, so I have to slide my hand up a lot on the screen to control the knob, because when I touch the knob of a joystick that is already down, it slides directly down, so I have to slide my hand up a lot to move it up. I want that knob not to slide down directly when I hold it, but to stay where I hold it, so that the knob allows me to go wherever I move it.
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of null (reading 'removeChild')' in or related to this line: 'self.active = false;' Line Number: 381
User prompt
Currently, after I level up and choose one of the options, my health is completely restored, I don't want this to happen. Also, my character's movement speed should increase by 4% every time I level up.
User prompt
When my character levels up, the options presented to him/her should be unique, meaning they should not be identical.
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of null (reading 'removeChild')' in or related to this line: 'if (this.life <= 0) {' Line Number: 867
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'call')' in or related to this line: 'Enemy.prototype.update.call(self);' Line Number: 257
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'update')' in or related to this line: 'Enemy.__super__.update.call(self);' Line Number: 257
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'call')' in or related to this line: 'Enemy.prototype.update.call(self);' Line Number: 257
User prompt
Right now when I start the game my background music doesn't start playing. Fix this. Also like magnets and bombs a chicken leg should appear on the screen every now and then. When my character picks up this chicken leg it should heal them for 30% of their maximum health.
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'apply')' in or related to this line: 'Enemy.prototype.update.apply(self);' Line Number: 226
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'call')' in or related to this line: 'Enemy.prototype.update.call(self);' Line Number: 226
User prompt
So edit my code to what I want.
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Bomb = Container.expand(function () {
var self = Container.call(this);
self.active = true;
var bombGraphics = self.attachAsset('bomb', {
anchorX: 0.5,
anchorY: 0.5,
width: 60,
height: 60,
tint: 0xff0000
});
self.update = function () {
if (!player || !self.active) {
return;
}
var dx = player.x - self.x;
var dy = player.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < 80) {
self.active = false;
// Kill all non-boss enemies on screen
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
if (enemy.type !== 'boss') {
var screenDx = Math.abs(enemy.x - player.x);
var screenDy = Math.abs(enemy.y - player.y);
if (screenDx < 1024 && screenDy < 1366) {
dropExpOrb(enemy.x, enemy.y);
enemy.destroy();
enemies.splice(i, 1);
}
}
}
LK.effects.flashScreen(0xff0000, 300);
if (self.parent) {
self.destroy();
}
return true;
}
};
return self;
});
var Bullet = Container.expand(function () {
var self = Container.call(this);
self.damage = 10;
self.speed = 15;
self.dirX = 0;
self.dirY = 0;
self.piercing = 1;
self.hitEnemies = [];
var bulletGraphics = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.update = function () {
// Seviye seçim ekranı açıkken hiçbir şey yapma
if (skillSelectionActive) {
return;
}
// Hareket
this.x += this.dirX * this.speed;
this.y += this.dirY * this.speed;
// Ekranın çok uzağına çıktıysa sil
var dx = this.x - player.x;
var dy = this.y - player.y;
if (Math.abs(dx) > 2000 || Math.abs(dy) > 2000) {
this.destroy();
var bi = bullets.indexOf(this);
if (bi >= 0) {
bullets.splice(bi, 1);
}
return;
}
// “Menzil” filtresi: bu top silahının menzili WEAPONS.ball.range
var maxRange = WEAPONS.ball.range * (player.weapons && player.weapons.ball ? player.weapons.ball.rngMul : 1);
// (Eğer o envanterde yoksa rngMul=1 varsaydık)
// Düşmana çarpma kontrolü & menzil filtresi
for (var i = enemies.length - 1; i >= 0; i--) {
var e = enemies[i];
if (this.intersects(e) && isWithinRange(e, maxRange)) {
damageEnemy(e, this.damage);
this.destroy();
var bi2 = bullets.indexOf(this);
if (bi2 >= 0) {
bullets.splice(bi2, 1);
}
return;
}
}
};
return self;
});
// ChickenLeg pickup class
var ChickenLeg = Container.expand(function () {
var self = Container.call(this);
self.active = true;
var chickenLegGraphics = self.attachAsset('chickenLeg', {
anchorX: 0.5,
anchorY: 0.5,
width: 60,
height: 60
});
self.update = function () {
if (!player || !self.active) {
return;
}
var dx = player.x - self.x;
var dy = player.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < 80) {
self.active = false;
// Heal player for 30% of max HP, but not above max HP
var healAmount = Math.floor(player.maxHp * 0.3);
player.hp = Math.min(player.hp + healAmount, player.maxHp);
LK.effects.flashObject(player, 0x00ff00, 300);
LK.getSound('pickup').play();
if (self.parent) {
self.destroy();
}
return true;
}
};
return self;
});
var Enemy = Container.expand(function () {
var self = Container.call(this);
// Normal zombie stats
self.hp = 16;
self.maxHp = 16;
self.damage = 8;
self.speed = 2;
self.expValue = 1;
self.type = 'normal';
var enemyGraphics = self.attachAsset('zombie', {
anchorX: 0.5,
anchorY: 0.5
});
self.takeDamage = function (amount) {
self.hp -= amount;
LK.effects.flashObject(self, 0xff0000, 200);
if (self.hp <= 0) {
return true; // Enemy died
}
return false; // Enemy still alive
};
self.update = function () {
if (!player || skillSelectionActive) {
return;
}
// Flip enemy graphic to face player
if (self.x < player.x) {
enemyGraphics.scaleX = 1;
} else if (self.x > player.x) {
enemyGraphics.scaleX = -1;
}
// 1) Oyuncuya olan vektörü bul
var dx = player.x - self.x;
var dy = player.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
// 2) Eğer düşman, oyuncuya 150 pikselden yakınsa hareket etme
if (dist > 150) {
// 3) Aksi halde 50px uzaktan hareket et
self.x += dx / dist * self.speed;
self.y += dy / dist * self.speed;
}
// Burada asla destroy() yok; sadece hareketi sınırlıyoruz
};
return self;
});
var TankZombie = Enemy.expand(function () {
var self = Enemy.call(this);
self.hp = 60;
self.maxHp = 60;
self.damage = 6;
self.speed = 1;
self.expValue = 2;
self.type = 'tank';
var graphics = self.attachAsset('tankZombie', {
anchorX: 0.5,
anchorY: 0.5
});
// Flip tank zombie to face player
self.update = function () {
if (!player || skillSelectionActive) return;
if (self.x < player.x) {
graphics.scaleX = 1;
} else if (self.x > player.x) {
graphics.scaleX = -1;
}
// Call base Enemy update
Enemy.call(self).update();
};
return self;
});
var FastZombie = Enemy.expand(function () {
var self = Enemy.call(this);
self.hp = 8;
self.maxHp = 8;
self.damage = 12;
self.speed = 8; // very fast (4x normal)
self.expValue = 1;
self.type = 'fast';
var graphics = self.attachAsset('fastZombie', {
anchorX: 0.5,
anchorY: 0.5
});
// Flip fast zombie to face player
self.update = function () {
if (!player || skillSelectionActive) return;
if (self.x < player.x) {
graphics.scaleX = 1;
} else if (self.x > player.x) {
graphics.scaleX = -1;
}
// Call base Enemy update
Enemy.call(self).update();
};
return self;
});
var Boss = Enemy.expand(function () {
var self = Enemy.call(this);
self.hp = 150;
self.maxHp = 150;
self.damage = 34;
self.speed = 1; // slow
self.expValue = 6;
self.type = 'boss';
var graphics = self.attachAsset('boss', {
anchorX: 0.5,
anchorY: 0.5
});
// Flip boss to face player
self.update = function () {
if (!player || skillSelectionActive) return;
if (self.x < player.x) {
graphics.scaleX = 1;
} else if (self.x > player.x) {
graphics.scaleX = -1;
}
// Call base Enemy update
Enemy.call(self).update();
};
return self;
});
var ExpOrb = Container.expand(function () {
var self = Container.call(this);
// 1) spawnTime kaydet
self.spawnTime = gameTime;
self.value = 1; // Each orb always gives 1 EXP
self.magnetSpeed = 0;
var orbGraphics = self.attachAsset('expOrb', {
anchorX: 0.5,
anchorY: 0.5
});
self.update = function () {
// ORB YAŞI (frame cinsinden)
var age = gameTime - self.spawnTime;
// 2) Eğer 10 saniye geçmişse (600 frame), orb’u yok et ve listeden çıkar
if (age >= 600) {
// yok et
if (self.parent) {
self.destroy();
}
var idx = expOrbs.indexOf(self);
if (idx >= 0) {
expOrbs.splice(idx, 1);
}
return;
}
// 3) Son 5 saniyede (age >= 300), yanıp sönme uygulaması
if (age >= 300) {
// kalan süre
var remaining = 600 - age; // 300’den 0’a kadar azalır
// blink periyodu: remaining / 50’ye bağlı (en hızlı 1 frame’lik periyot)
var blinkInterval = Math.ceil(remaining / 50);
if (blinkInterval < 1) {
blinkInterval = 1;
}
// yaşa göre çift/tek periyoda bölerek görünürlüğü değiştir
var phase = Math.floor(age / blinkInterval);
self.visible = phase % 2 === 0;
} else {
// son 5 saniye değilse görünür olsun
self.visible = true;
}
// 4) Normal manyetik çekim hareketi
if (!player || self.magnetSpeed === 0) {
return;
}
var dx = player.x - self.x;
var dy = player.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 0) {
self.x += dx / dist * self.magnetSpeed;
self.y += dy / dist * self.magnetSpeed;
}
};
return self;
});
var Joystick = Container.expand(function () {
var self = Container.call(this);
self.active = false;
self.dirX = 0;
self.dirY = 0;
var base = self.attachAsset('joystickBase', {
anchorX: 0.5,
anchorY: 0.5
});
base.alpha = 0.5;
var knob = self.attachAsset('joystickKnob', {
anchorX: 0.5,
anchorY: 0.5
});
knob.alpha = 0.7;
self.setKnobPosition = function (x, y) {
var dx = x - base.x;
var dy = y - base.y;
var dist = Math.sqrt(dx * dx + dy * dy);
var maxDist = 60;
if (dist > maxDist) {
dx = dx / dist * maxDist;
dy = dy / dist * maxDist;
}
knob.x = dx;
knob.y = dy;
self.dirX = dx / maxDist;
self.dirY = dy / maxDist;
};
self.reset = function () {
knob.x = 0;
knob.y = 0;
self.dirX = 0;
self.dirY = 0;
self.active = false;
};
return self;
});
var Magnet = Container.expand(function () {
var self = Container.call(this);
self.active = true;
var magnetGraphics = self.attachAsset('magnet', {
anchorX: 0.5,
anchorY: 0.5,
width: 60,
height: 60,
tint: 0x0099ff
});
self.update = function () {
if (!player || !self.active) {
return;
}
var dx = player.x - self.x;
var dy = player.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < 80) {
self.active = false;
// Magnetize all exp orbs on screen
for (var i = 0; i < expOrbs.length; i++) {
var orb = expOrbs[i];
var orbDx = Math.abs(orb.x - player.x);
var orbDy = Math.abs(orb.y - player.y);
if (orbDx < 1024 && orbDy < 1366) {
orb.magnetSpeed = 20;
}
}
if (self.parent) {
self.destroy();
}
return true;
}
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
self.level = 1;
self.exp = 0;
self.expToNext = 10;
self.hp = 100;
self.maxHp = 100;
self.damage = 10;
self.fireRate = 30;
self.bulletSpeed = 15;
self.moveSpeed = 5;
self.pickupRange = 100;
self.lastFire = 0;
/* ===== WEAPON INVENTORY ===== */
self.weapons = {}; // key → instance
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.takeDamage = function (amount) {
self.hp -= amount;
LK.effects.flashObject(self, 0xff0000, 300);
if (self.hp <= 0) {
LK.showGameOver();
}
};
self.gainExp = function (amount) {
// Add exp orbs
self.exp += amount;
// Level up if exp orbs >= current level
while (self.exp >= self.level) {
self.exp -= self.level;
self.levelUp();
}
};
self.update = function () {
// Flip player graphic based on movement direction
if (self.lastX === undefined) self.lastX = self.x;
if (self.x > self.lastX) {
playerGraphics.scaleX = 1;
} else if (self.x < self.lastX) {
playerGraphics.scaleX = -1;
}
self.lastX = self.x;
for (var k in self.weapons) {
var inst = self.weapons[k],
meta = WEAPONS[k];
if (--inst.cdCnt <= 0) {
fireWeapon(k, inst, meta);
inst.cdCnt = meta.cd;
}
}
};
self.levelUp = function () {
self.level++;
// self.exp is now handled in gainExp, do not reset here
self.expToNext = self.level * 15;
self.maxHp += 10;
// Do NOT restore full health on level up
// self.hp = self.maxHp;
// Increase movement speed by 4% per level up
self.moveSpeed *= 1.04;
LK.getSound('levelup').play();
showSkillSelection();
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x111111
});
/****
* Game Code
****/
/* ==== UNIVERSAL HELPERS ==== */
function isWithinRange(e, maxRange) {
var dx = e.x - player.x;
var dy = e.y - player.y;
return dx * dx + dy * dy <= maxRange * maxRange;
}
function addWeapon(key) {
// <-- artık global
if (player && Object.keys(player.weapons).length >= 6) {
return; // Zaten 6 silah varsa yeni eklemeye izin verme
}
var m = WEAPONS[key];
var target = player ? player : {
weapons: {}
}; // sınıf kurulumunda da çalışsın
target.weapons[key] = {
cd: m.cd,
cdCnt: m.cd,
dmgMul: 1,
rngMul: 1,
sizeMul: 1,
amount: 1,
upgrade: 0,
enchTaken: []
};
}
function rand(min, max) {
return min + Math.random() * (max - min);
}
function distSq(a, b) {
var dx = a.x - b.x,
dy = a.y - b.y;
return dx * dx + dy * dy;
}
function unitDir(from, to) {
var dx = to.x - from.x,
dy = to.y - from.y,
d = Math.sqrt(dx * dx + dy * dy);
return {
dx: dx / d,
dy: dy / d,
len: d
};
}
/* ==== WEAPON META TABLE ==== */
var WEAPONS = {
sword: {
cd: 120,
dmg: 5,
range: 250,
type: 'melee',
ench: ["Sword Damage+", "Sword Attack Speed+", "Sword Range+", "Sword Size+"],
up: ["Sword +1", "Sword +2", "Sword +3"]
},
boomerang: {
cd: 180,
dmg: 3,
range: 600,
type: 'boomerang',
ench: ["Boomerang Damage+", "Boomerang Attack Speed+", "Boomerang Range+", "Boomerang Size+"],
up: ["Boomerang +1", "Boomerang +2", "Boomerang +3"]
},
ball: {
cd: 180,
dmg: 3,
range: 600,
type: 'ball',
ench: ["Ball Damage+", "Ball Attack Speed+", "Ball Range+", "Ball Size+"],
up: ["Ball +1", "Ball +2", "Ball +3"]
},
rocket: {
cd: 240,
dmg: 10,
range: 600,
type: 'rocket',
ench: ["Rocket Damage+", "Rocket Attack Speed+", "Rocket Range+", "Rocket Size+"],
up: ["Rocket +1", "Rocket +2", "Rocket +3"]
},
brick: {
cd: 180,
dmg: 8,
range: 600,
type: 'brick',
ench: ["Brick Damage+", "Brick Attack Speed+", "Brick Range+", "Brick Size+"],
up: ["Back 75°", "Front 45°", "Back 45°"]
},
lightning: {
cd: 180,
dmg: 14,
range: 600,
type: 'lightning',
ench: ["Lightning Damage+", "Lightning Attack Speed+", "Lightning Range+", "Lightning Size+"],
up: ["Lightning +1", "Lightning +2", "Lightning +3"]
},
aura: {
cd: 60,
dmg: 4,
range: 300,
type: 'aura',
ench: ["Aura Damage+", "Aura Attack Speed+", "Aura Range+", "Aura Size+"],
up: ["Slow 25%", "Slow 50%", "Slow 75%"]
},
molotov: {
cd: 180,
dmg: 8,
range: 600,
type: 'molotov',
ench: ["Molotov Damage+", "Molotov Attack Speed+", "Molotov Range+", "Molotov Size+"],
up: ["Molotov +1", "Molotov +2", "Molotov +3"]
},
shuriken: {
cd: 180,
dmg: 3,
range: 300,
type: 'shuriken',
ench: ["Shuriken Damage+", "Shuriken Attack Speed+", "Shuriken Range+", "Shuriken Size+"],
up: ["Shuriken +1", "Shuriken +2", "Shuriken +3"]
}
};
var player;
var enemies = [];
var bullets = [];
var expOrbs = [];
var joystick;
var gameTime = 0;
var waveNumber = 1;
var bossSpawned = false;
var selectedSkills = [];
var camera = {
x: 0,
y: 0
};
var gameContainer;
var skillSelectionActive = false;
var pickups = [];
var lastPickupSpawn = 0;
// Initialize game world
gameContainer = game.addChild(new Container());
// Tile seamless background image to cover the visible area and follow the camera
var bgTileAsset = LK.getAsset('seamlessBackGround', {
anchorX: 0,
anchorY: 0
});
var bgTileWidth = bgTileAsset.width;
var bgTileHeight = bgTileAsset.height;
var bgTilesX = Math.ceil(2048 / bgTileWidth) + 2; // +2 for safe margin
var bgTilesY = Math.ceil(2732 / bgTileHeight) + 2;
var backgroundTiles = [];
for (var i = 0; i < bgTilesX; i++) {
for (var j = 0; j < bgTilesY; j++) {
var tile = LK.getAsset('seamlessBackGround', {
anchorX: 0,
anchorY: 0
});
tile.x = i * bgTileWidth;
tile.y = j * bgTileHeight;
gameContainer.addChild(tile);
backgroundTiles.push(tile);
}
}
// Create player
player = gameContainer.addChild(new Player());
player.x = 1024;
player.y = 1366;
addWeapon('sword');
// Create joystick
joystick = new Joystick();
joystick.x = 0;
joystick.y = -200;
LK.gui.bottom.addChild(joystick);
// UI Elements
var timerText = new Text2('00:00', {
size: 80,
fill: 0xFFFFFF
});
timerText.anchor.set(0.5, 0);
LK.gui.top.addChild(timerText);
var levelText = new Text2('Level 1', {
size: 60,
fill: 0xFFFF00
});
levelText.anchor.set(0, 0);
levelText.y = 100;
levelText.x = 50;
LK.gui.top.addChild(levelText);
var hpText = new Text2('HP: 100/100', {
size: 60,
fill: 0xFF0000
});
hpText.anchor.set(1, 0);
hpText.y = 100;
hpText.x = -50;
LK.gui.top.addChild(hpText);
// Helper: get max zombies allowed on screen
function getMaxZombies() {
var elapsedSeconds = Math.floor(gameTime / 60);
var maxZ = 20 + Math.floor(elapsedSeconds / 30) * 2;
return maxZ;
}
// Spawn functions
function spawnEnemy(type, x, y) {
var enemy;
switch (type) {
case 'fast':
enemy = new FastZombie();
break;
case 'tank':
enemy = new TankZombie();
break;
case 'boss':
enemy = new Boss();
break;
default:
enemy = new Enemy();
}
enemy.x = x;
enemy.y = y;
enemies.push(enemy);
gameContainer.addChild(enemy);
}
function spawnWave() {
var spawnCount = 5 + waveNumber * 2;
var spawnRadius = 1500;
for (var i = 0; i < spawnCount; i++) {
// Check if we've reached the enemy limit
if (enemies.length >= getMaxZombies()) {
break;
}
var angle = Math.random() * Math.PI * 2;
var x = player.x + Math.cos(angle) * spawnRadius;
var y = player.y + Math.sin(angle) * spawnRadius;
// Determine zombie type by probability
var randType = Math.random();
var type = 'normal';
if (randType < 0.2) {
type = 'tank';
} else if (randType < 0.3) {
type = 'fast';
} else {
type = 'normal';
}
spawnEnemy(type, x, y);
}
}
function dropExpOrb(x, y) {
var orb = new ExpOrb();
orb.x = x;
orb.y = y;
// orb.value is always 1 in ExpOrb class
expOrbs.push(orb);
gameContainer.addChild(orb);
}
/* =============================================================== */
/* NINE-WEAPON FIRE / PROJECTILES */
/* =============================================================== */
function nearestEnemy() {
var best = null,
bestD = 1e9;
for (var i = 0; i < enemies.length; i++) {
var d = distSq(player, enemies[i]);
if (d < bestD) {
best = enemies[i];
bestD = d;
}
}
return best;
}
function damageEnemy(e, dmg) {
// Play hit sound on every hit
LK.getSound('hit').play();
if (e.takeDamage(dmg)) {
// Play death sound (if you have a death sound asset, e.g. 'death')
if (LK.getSound('death')) {
LK.getSound('death').play();
}
// Ölünce exp orb düşür:
for (var expi = 0; expi < (e.expValue || 1); expi++) {
dropExpOrb(e.x + rand(-10, 10), e.y + rand(-10, 10));
}
// Sonra düşmanı kaldır ve yok et:
var idx = enemies.indexOf(e);
enemies.splice(idx, 1);
e.destroy();
}
}
/* ---- sword (melee slash) ---- */
function swingSword(inst) {
var sorted = enemies.slice().sort(function (a, b) {
return distSq(player, a) - distSq(player, b);
});
if (sorted.length === 0) {
return;
}
for (var n = 0; n < inst.amount; n++) {
var idx = n < sorted.length ? n : 0;
var target = sorted[idx];
var dir = unitDir(player, target);
var arc = gameContainer.addChild(new Container());
arc.x = player.x;
arc.y = player.y;
arc.attachAsset('swordHit', {
anchorX: 0,
anchorY: 0.5,
rotation: Math.atan2(dir.dy, dir.dx),
scaleX: inst.sizeMul,
scaleY: inst.sizeMul
});
arc.life = 10;
arc.dmg = WEAPONS.sword.dmg * inst.dmgMul;
arc.hitList = [];
arc.update = function () {
if (--this.life <= 0) {
if (this.parent) {
this.destroy();
}
return;
}
var maxRange = WEAPONS.sword.range * inst.rngMul;
for (var i = enemies.length - 1; i >= 0; i--) {
var e = enemies[i];
// hem arc.intersects hem oyuncudan menzil kontrolü
if (this.hitList.indexOf(e) === -1 && this.intersects(e) && isWithinRange(e, maxRange)) {
this.hitList.push(e);
damageEnemy(e, this.dmg);
}
}
};
}
}
/* ---- boomerang ---- */
function fireBoomerang(inst) {
var target = nearestEnemy();
if (!target) {
return;
}
var dir = unitDir(player, target);
// Bu silahın menzilini WEAPONS tablosundan alıp, inst.rngMul ile ölçekleyebiliriz:
var maxRange = WEAPONS.boomerang.range * inst.rngMul;
for (var n = 0; n < inst.amount; n++) {
var p = gameContainer.addChild(new Container());
p.attachAsset('boomerang', {
anchorX: 0.5,
anchorY: 0.5
});
p.x = player.x;
p.y = player.y;
p.dirX = dir.dx;
p.dirY = dir.dy;
p.speed = 12;
p.dmg = WEAPONS.boomerang.dmg * inst.dmgMul;
p.life = 300;
p.update = function () {
if (skillSelectionActive) {
return;
}
// 1) Hareket
this.x += this.dirX * this.speed;
this.y += this.dirY * this.speed;
// 2) “life” 150’de geri dönüş
if (--this.life === 150) {
var u = unitDir(this, player);
this.dirX = u.dx;
this.dirY = u.dy;
}
// 3) Boomerang ekranın çok dışına çıktıysa sil
var dx = this.x - player.x;
var dy = this.y - player.y;
if (Math.abs(dx) > 2000 || Math.abs(dy) > 2000) {
if (this.parent) {
this.destroy();
}
var idx = bullets.indexOf(this);
if (idx >= 0) {
bullets.splice(idx, 1);
}
return;
}
// 4) Düşmanlara çarpma kontrolü & menzil filtresi
for (var i = enemies.length - 1; i >= 0; i--) {
var e = enemies[i];
// e, oyuncudan maxRange uzaklık içindeyse vur:
if (this.intersects(e) && isWithinRange(e, maxRange)) {
damageEnemy(e, this.dmg);
this.destroy();
var idx2 = bullets.indexOf(this);
if (idx2 >= 0) {
bullets.splice(idx2, 1);
}
return;
}
}
// 5) “life” sıfırlandıysa sil
if (this.life <= 0) {
if (this.parent) {
this.destroy();
}
var idx3 = bullets.indexOf(this);
if (idx3 >= 0) {
bullets.splice(idx3, 1);
}
}
};
bullets.push(p);
}
}
/* ---- top (rebound ball) ---- */
function fireBall(inst) {
var target = nearestEnemy();
if (!target) {
return;
}
var dir = unitDir(player, target);
for (var n = 0; n < inst.amount; n++) {
var p = new Bullet();
p.x = player.x;
p.y = player.y;
p.dirX = dir.dx;
p.dirY = dir.dy;
p.damage = 12 * inst.dmgMul;
p.speed = 14;
bullets.push(p);
gameContainer.addChild(p);
}
}
/* ---- rocket ---- */
function fireRocket(inst) {
var target = nearestEnemy();
if (!target) {
return;
}
var dir = unitDir(player, target);
// Bu silahın menzili:
var maxRange = WEAPONS.rocket.range * inst.rngMul;
for (var n = 0; n < inst.amount; n++) {
var p = gameContainer.addChild(new Container());
p.attachAsset('rocket', {
anchorX: 0.5,
anchorY: 0.5
});
p.x = player.x;
p.y = player.y;
p.dirX = dir.dx;
p.dirY = dir.dy;
p.speed = 10;
p.dmg = WEAPONS.rocket.dmg * inst.dmgMul;
p.update = function () {
if (skillSelectionActive) {
return;
}
// 1) Hareket
this.x += this.dirX * this.speed;
this.y += this.dirY * this.speed;
// 2) Düşmana çarpma kontrolü & menzil filtresi
for (var i = enemies.length - 1; i >= 0; i--) {
var e = enemies[i];
// Eğer bu e, oyuncudan maxRange uzaklık içindeyse AoE hasar uygula
if (this.intersects(e) && isWithinRange(e, maxRange)) {
LK.getSound('rocketBoom').play();
// a) Dairesel patlama efekti:
// Yarıçapı örneğin 80px olan turuncu bir daire çiziyoruz,
// yarım saniye sonra yok olmalı (30 frame = 0.5s).
var explosion = gameContainer.addChild(new Container());
// Daire efektini LK.getAsset ile oluşturuyoruz:
var gfx = LK.getAsset('molotovFlame', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: inst.rngMul * (80 / 70),
// 70: orijinal yarıçap, 80: istenen yarıçap
scaleY: inst.rngMul * (80 / 70),
alpha: 0.6,
tint: 0xFFAA00
});
explosion.addChild(gfx);
explosion.x = this.x;
explosion.y = this.y;
explosion.life = 30; // 30 frame = 0.5 saniye (60FPS varsayımıyla)
explosion.update = function () {
if (--this.life <= 0) {
this.destroy();
} else {
// Her frame biraz şeffaflaştırmak için:
this.children[0].alpha = this.life / 30 * 0.6;
}
};
// b) AoE hasar: yine sadece menzil içindekileri vur
for (var k = enemies.length - 1; k >= 0; k--) {
var e2 = enemies[k];
if (distSq(this, e2) < 16000 && isWithinRange(e2, maxRange)) {
damageEnemy(e2, this.dmg);
}
}
// c) Bu roketi sil
if (this.parent) {
this.destroy();
}
var bi = bullets.indexOf(this);
if (bi >= 0) {
bullets.splice(bi, 1);
}
return;
}
}
// 3) Ekranın dışına çıkarsa sil
var dx = this.x - player.x;
var dy = this.y - player.y;
if (Math.abs(dx) > 2000 || Math.abs(dy) > 2000) {
if (this.parent) {
this.destroy();
}
var bi2 = bullets.indexOf(this);
if (bi2 >= 0) {
bullets.splice(bi2, 1);
}
return;
}
};
bullets.push(p);
}
}
/* ---- brick ---- */
function throwBrick(inst, angDeg) {
var rad = angDeg * Math.PI / 180;
var p = gameContainer.addChild(new Container());
p.attachAsset('brick', {
anchorX: 0.5,
anchorY: 0.5
});
p.x = player.x;
p.y = player.y;
p.vx = Math.cos(rad) * 14;
p.vy = Math.sin(rad) * 14;
p.g = 0.3;
p.dmg = WEAPONS.brick.dmg * inst.dmgMul;
// Bu silahın menzili:
var maxRange = WEAPONS.brick.range * inst.rngMul;
p.update = function () {
if (skillSelectionActive) {
return;
}
// 1) Yerçekimi ve hareket
this.vy += this.g;
this.x += this.vx;
this.y += this.vy;
// 2) Düşmana çarpma kontrolü & menzil filtresi
for (var i = enemies.length - 1; i >= 0; i--) {
var e = enemies[i];
if (this.intersects(e) && isWithinRange(e, maxRange)) {
damageEnemy(e, this.dmg);
if (this.parent) {
this.destroy();
}
return;
}
}
// 3) Belirli mesafeden uzaklaşırsa yok et
var dx = this.x - player.x;
var dy = this.y - player.y;
if (Math.abs(dx) > 2000 || Math.abs(dy) > 2000) {
if (this.parent) {
this.destroy();
}
return;
}
};
}
/* ---- lightning ---- */
function castLightning(inst) {
// 1) Menzildeki düşmanları filtrele
var maxRange = WEAPONS.lightning.range * inst.rngMul;
var candidates = enemies.filter(function (e) {
var dx = e.x - player.x;
var dy = e.y - player.y;
return dx * dx + dy * dy <= maxRange * maxRange;
});
if (candidates.length === 0) {
return;
}
// 2) Rastgele birini seç
var victim = candidates[Math.floor(Math.random() * candidates.length)];
// 3) Efekti ekle
var l = gameContainer.addChild(new Container());
l.attachAsset('lightning', {
anchorX: 0.5,
anchorY: 1
});
l.x = victim.x;
l.y = victim.y;
l.life = 15;
l.update = function () {
if (skillSelectionActive) {
return;
}
if (--this.life === 14) {
damageEnemy(victim, WEAPONS.lightning.dmg * inst.dmgMul);
}
if (this.life <= 0) {
if (this.parent) {
this.destroy();
}
}
};
}
/* ---- aura ---- */
var auraField = null;
function ensureAura(inst) {
// 1) Sadece ilk defa oluşturulacak:
if (!auraField) {
auraField = player.addChild(new Container());
auraField.attachAsset('auraField', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.3
});
// Oyuncunun tam ortası (yerel koordinat):
auraField.x = 0;
auraField.y = 0;
}
// 2) Hasar uygulama kısmı (oyuncudan r uzaklıktaysa vur):
var r = WEAPONS.aura.range * inst.rngMul;
for (var i = enemies.length - 1; i >= 0; i--) {
var e = enemies[i];
var dx = e.x - player.x;
var dy = e.y - player.y;
if (dx * dx + dy * dy < r * r) {
damageEnemy(e, inst.dmgMul * 5);
}
}
}
/* ---- molotov ---- */
function throwMolotov(inst) {
var a = Math.random() * Math.PI * 2,
d = rand(300, 600),
tx = player.x + Math.cos(a) * d,
ty = player.y + Math.sin(a) * d;
var p = gameContainer.addChild(new Container());
p.attachAsset('molotov', {
anchorX: 0.5,
anchorY: 0.5
});
p.x = player.x;
p.y = player.y;
var u = unitDir(p, {
x: tx,
y: ty
});
p.dirX = u.dx;
p.dirY = u.dy;
p.speed = 16;
p.life = 60;
p.update = function () {
if (skillSelectionActive) {
return;
}
this.x += this.dirX * this.speed;
this.y += this.dirY * this.speed;
if (--this.life <= 0) {
spawnFlame(tx, ty, inst);
if (this.parent) {
this.destroy();
}
}
};
bullets.push(p);
}
/* ---- molotov flame ---- */
function spawnFlame(x, y, inst) {
var f = gameContainer.addChild(new Container());
f.attachAsset('molotovFlame', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.4
});
f.x = x;
f.y = y;
f.life = 60;
f.dmg = WEAPONS.molotov.dmg * inst.dmgMul;
// Molotov alanının menzili (örnek olarak 70→çevrede yarıçap 70px)
var maxFlameRange = 70 * inst.rngMul;
f.update = function () {
if (skillSelectionActive) {
return;
}
// 1) Düşmana hasar kontrolü & menzil filtresi
for (var i = enemies.length - 1; i >= 0; i--) {
var e = enemies[i];
// “distSq(f,e) < 4900” yerine “4900 = 70^2” diyorduk.
// Şimdi ek olarak oyuncudan menzil kontrolü de ekleyelim:
if (distSq(f, e) < maxFlameRange * maxFlameRange && isWithinRange(e, maxFlameRange)) {
damageEnemy(e, this.dmg);
}
}
// 2) Ömür kontrolü
if (--this.life <= 0) {
if (this.parent) {
this.destroy();
}
return;
}
// 3) Ekranın uzağına çıktıysa sil
var dx = this.x - player.x;
var dy = this.y - player.y;
if (Math.abs(dx) > 2000 || Math.abs(dy) > 2000) {
if (this.parent) {
this.destroy();
}
return;
}
};
}
/* ---- shuriken ring ---- */
var shurikenObjs = [];
function maintainShurikens(inst) {
if (shurikenObjs.length !== inst.amount) {
shurikenObjs.forEach(function (s) {
if (s.parent) {
s.destroy();
}
});
shurikenObjs = [];
var n = inst.amount,
r = WEAPONS.shuriken.range * inst.rngMul; // şuriken menzili
for (var i = 0; i < n; i++) {
var s = gameContainer.addChild(new Container());
s.attachAsset('shuriken', {
anchorX: 0.5,
anchorY: 0.5
});
s.angle = i / n * Math.PI * 2;
s.update = function () {
if (skillSelectionActive) {
return;
}
this.angle += 0.15;
this.x = player.x + Math.cos(this.angle) * r;
this.y = player.y + Math.sin(this.angle) * r;
// Her bir düşmanı kontrol et: hem shuriken çarpışma hem oyuncudan menzil
for (var k = enemies.length - 1; k >= 0; k--) {
var e = enemies[k];
if (this.intersects(e) && isWithinRange(e, r)) {
damageEnemy(e, WEAPONS.shuriken.dmg * inst.dmgMul);
}
}
};
shurikenObjs.push(s);
}
}
}
/* ---- ana fireWeapon anahtarı ---- */
function fireWeapon(key, inst, meta) {
switch (meta.type) {
case 'melee':
swingSword(inst);
break;
case 'boomerang':
fireBoomerang(inst);
break;
case 'ball':
fireBall(inst);
break;
case 'rocket':
fireRocket(inst);
break;
case 'brick':
throwBrick(inst, 75);
if (inst.upgrade > 0) {
throwBrick(inst, -75);
}
if (inst.upgrade > 1) {
throwBrick(inst, 45);
}
if (inst.upgrade > 2) {
throwBrick(inst, -45);
}
break;
case 'lightning':
for (var n = 0; n < inst.amount; n++) {
castLightning(inst);
}
break;
case 'aura':
ensureAura(inst);
break;
case 'molotov':
for (var n = 0; n < inst.amount; n++) {
throwMolotov(inst);
}
break;
case 'shuriken':
maintainShurikens(inst);
break;
}
}
function showSkillSelection() {
skillSelectionActive = true;
// 1) Yeni bir Overlay (seçim ekranı) oluşturuyoruz
var ov = game.addChild(new Container());
ov.x = 1024;
ov.y = 1366;
var choices = [];
// 2) Eğer oyuncu seviyesi 5'in katı ise (5,10,15,...)
if (player.level % 5 === 0) {
var ownedCount = Object.keys(player.weapons).length;
// 2.a) Hâlâ < 6 silah sahibi ise: yeni silah açma seçenekleri
if (ownedCount < 6) {
// Kilidi açılmamış silahlar havuzunu al
var pool = Object.keys(WEAPONS).filter(function (key) {
return !player.weapons[key];
});
// Havuzdan rastgele 3 silah göster, her biri benzersiz
while (choices.length < 3 && pool.length > 0) {
var rnd = Math.floor(Math.random() * pool.length);
choices.push(pool.splice(rnd, 1)[0]);
}
} else {
// 2.b) Zaten 6 silah sahibi ise: önce silahların upgrade durumlarını kontrol et
var upgradePool = [];
Object.keys(player.weapons).forEach(function (key) {
var inst = player.weapons[key];
if (inst.upgrade < 3) {
// Eğer bu silah hâlâ < 3 aşama güçlendirilmişse,
// “bu silahın bir sonraki upgrade aşaması” havuza eklenir.
upgradePool.push({
w: key
});
}
});
if (upgradePool.length > 0) {
// 2.b.i) En az bir silah yükseltmesi kalmış demektir:
// Rastgele en fazla 3 tane “silah güçlendirme” seçeneği göster, her biri benzersiz
while (choices.length < 3 && upgradePool.length > 0) {
var rnd2 = Math.floor(Math.random() * upgradePool.length);
choices.push({
w: upgradePool[rnd2].w,
type: "upgrade"
});
upgradePool.splice(rnd2, 1);
}
} else {
// 2.b.ii) Tüm 6 silah zaten upgrade === 3 ise:
// Bu aşamadan sonra artık sadece efsun kartı göster.
// Her kart benzersiz olmalı (hem silah hem efsun kombinasyonu)
var ownedKeys2 = Object.keys(player.weapons);
var usedPairs = [];
var attempts = 0;
while (choices.length < 3 && attempts < 20) {
var randomKey2 = ownedKeys2[Math.floor(Math.random() * ownedKeys2.length)];
var enchList = WEAPONS[randomKey2].ench;
var rnd3 = enchList[Math.floor(Math.random() * enchList.length)];
var pairKey = randomKey2 + "|" + rnd3;
if (usedPairs.indexOf(pairKey) === -1) {
choices.push({
w: randomKey2,
e: rnd3
});
usedPairs.push(pairKey);
}
attempts++;
}
}
}
} else {
// 3) Seviye 5'in katı değilse: doğrudan efsun kartları göster
// Her kart benzersiz olmalı (hem silah hem efsun kombinasyonu)
var ownedKeys = Object.keys(player.weapons);
var usedPairs2 = [];
var attempts2 = 0;
while (choices.length < 3 && attempts2 < 20) {
var randomKey = ownedKeys[Math.floor(Math.random() * ownedKeys.length)];
var enchList = WEAPONS[randomKey].ench;
var rnd4 = enchList[Math.floor(Math.random() * enchList.length)];
var pairKey2 = randomKey + "|" + rnd4;
if (usedPairs2.indexOf(pairKey2) === -1) {
choices.push({
w: randomKey,
e: rnd4
});
usedPairs2.push(pairKey2);
}
attempts2++;
}
}
// 4) choices dizisini “3 adet kart” olarak UI’da çizelim
choices.forEach(function (c, idx) {
var card = ov.addChild(new Container());
card.attachAsset('skillCard', {
anchorX: 0.5,
anchorY: 0.5
});
card.x = (idx - 1) * 450;
card.y = 0;
var label, fn;
if (typeof c === "string") {
// c, yeni kilidi açılacak silahın anahtarı (ör. "boomerang")
var key = c;
var own = !!player.weapons[key];
if (!own) {
// Hâlâ envanterde yoksa “Unlock <silah adı>”
label = "Unlock " + key;
fn = function fn() {
addWeapon(key);
};
} else if (player.weapons[key].upgrade < 3) {
// Silah zaten varsa ve upgrade < 3 ise:
label = WEAPONS[key].up[player.weapons[key].upgrade];
fn = function fn() {
player.weapons[key].upgrade++;
player.weapons[key].amount++;
};
} else {
// Eğer upgrade === 3’e ulaşmışsa:
label = "No Option";
fn = function fn() {};
}
} else if (c.type === "upgrade") {
// c = { w: "sword", type:"upgrade" }
var wkey = c.w;
label = WEAPONS[wkey].up[player.weapons[wkey].upgrade];
fn = function fn() {
player.weapons[wkey].upgrade++;
player.weapons[wkey].amount++;
};
} else {
// c = { w: "<silahAnahtarı>", e: "<SilahName> Damage+" veya "<SilahName> Attack Speed+" vb. }
var w2 = c.w;
var efsun = c.e;
label = efsun;
fn = function fn() {
var inst = player.weapons[w2];
// Efsun metni "<SilahName> Damage+" ile bitiyorsa hasar çarpanını %10 artır:
if (efsun.endsWith(" Damage+")) {
inst.dmgMul *= 1.1;
}
// Efsun metni "<SilahName> Attack Speed+" ile bitiyorsa cd süresini %10 azalt:
if (efsun.endsWith(" Attack Speed+")) {
inst.cd *= 0.9;
}
// Efsun metni "<SilahName> Range+" ile bitiyorsa menzil çarpanını %10 artır:
if (efsun.endsWith(" Range+")) {
inst.rngMul *= 1.1;
}
// Efsun metni "<SilahName> Size+" ile bitiyorsa boyut çarpanını %10 artır:
if (efsun.endsWith(" Size+")) {
inst.sizeMul *= 1.1;
}
};
}
var txt = new Text2(label, {
size: 40,
fill: 0xffffff
});
txt.anchor.set(0.5);
card.addChild(txt);
card.down = function () {
fn();
ov.destroy();
skillSelectionActive = false;
levelText.setText('Level ' + player.level);
};
});
}
// Input handling
// Joystick drag offset variables
var joystickDragOffsetX = 0;
var joystickDragOffsetY = 0;
game.down = function (x, y, obj) {
if (skillSelectionActive) {
return;
}
var localPos = LK.gui.bottom.toLocal({
x: x,
y: y
});
// Only activate joystick if touch is in lower part of screen (y > 2000 in game coordinates)
if (localPos.y > 0) {
joystick.active = true;
// Calculate offset from joystick center to touch point
joystickDragOffsetX = localPos.x - joystick.x;
joystickDragOffsetY = localPos.y - joystick.y;
// Set knob to where the user touched
joystick.setKnobPosition(joystickDragOffsetX, joystickDragOffsetY);
}
};
game.move = function (x, y, obj) {
if (!joystick.active || skillSelectionActive) {
return;
}
var localPos = LK.gui.bottom.toLocal({
x: x,
y: y
});
// Move knob relative to where the user first touched
var dx = localPos.x - joystick.x;
var dy = localPos.y - joystick.y;
joystick.setKnobPosition(dx, dy);
};
game.up = function (x, y, obj) {
joystick.reset();
joystickDragOffsetX = 0;
joystickDragOffsetY = 0;
};
// Track best survival time
var bestSurvivalTime = parseInt(storage.get('bestTime') || "0", 10);
var showBestTimeText = null;
// Game update
game.update = function () {
if (skillSelectionActive) {
return;
}
gameTime++;
// Update timer → geçen süreyi göster
var elapsedSeconds = Math.floor(gameTime / 60);
var minutes = Math.floor(elapsedSeconds / 60);
var seconds = elapsedSeconds % 60;
timerText.setText((minutes < 10 ? '0' + minutes : minutes) + ':' + (seconds < 10 ? '0' + seconds : seconds));
// On game over, update best time and show it
if (player.hp <= 0) {
if (elapsedSeconds > bestSurvivalTime) {
bestSurvivalTime = elapsedSeconds;
storage.set('bestTime', bestSurvivalTime);
}
// Show best time on screen (if not already shown)
if (!showBestTimeText) {
var bestMin = Math.floor(bestSurvivalTime / 60);
var bestSec = bestSurvivalTime % 60;
showBestTimeText = new Text2("Longest Survival: " + (bestMin < 10 ? '0' + bestMin : bestMin) + ":" + (bestSec < 10 ? '0' + bestSec : bestSec), {
size: 100,
fill: 0xFFD700
});
showBestTimeText.anchor.set(0.5, 0.5);
showBestTimeText.x = 1024;
showBestTimeText.y = 800;
LK.gui.center.addChild(showBestTimeText);
}
} else if (showBestTimeText) {
// Remove best time text if game restarts
showBestTimeText.destroy();
showBestTimeText = null;
}
// Update UI
hpText.setText('HP: ' + player.hp + '/' + player.maxHp);
// Show exp orbs and required exp for next level
levelText.setText('Level ' + player.level + ' EXP: ' + player.exp + '/' + player.level);
// Player movement
if (joystick.active) {
player.x += joystick.dirX * player.moveSpeed;
player.y += joystick.dirY * player.moveSpeed;
}
/* Fire weapons / aura etc. */
player.update();
// Camera follow player
camera.x = player.x - 1024;
camera.y = player.y - 1366;
gameContainer.x = -camera.x;
gameContainer.y = -camera.y;
// Update background tiles to always cover the visible area
if (backgroundTiles && backgroundTiles.length) {
var startX = Math.floor(camera.x / bgTileWidth) * bgTileWidth;
var startY = Math.floor(camera.y / bgTileHeight) * bgTileHeight;
var idx = 0;
for (var i = 0; i < bgTilesX; i++) {
for (var j = 0; j < bgTilesY; j++) {
var tile = backgroundTiles[idx++];
tile.x = startX + i * bgTileWidth;
tile.y = startY + j * bgTileHeight;
}
}
}
// Spawn waves
if (gameTime % 300 === 0) {
waveNumber++;
spawnWave();
}
// Boss zombie spawns every 60 seconds, number increases by 1 each time
if (typeof bossWaveCount === "undefined") bossWaveCount = 0;
if (gameTime > 0 && gameTime % 3600 === 0) {
bossWaveCount++;
var bossesToSpawn = bossWaveCount;
var angleStep = Math.PI * 2 / bossesToSpawn;
var bossRadius = 800;
for (var b = 0; b < bossesToSpawn; b++) {
var angle = b * angleStep + Math.random() * angleStep * 0.5;
var bx = player.x + Math.cos(angle) * bossRadius;
var by = player.y + Math.sin(angle) * bossRadius;
// Only spawn if under zombie limit
if (enemies.length < getMaxZombies()) {
spawnEnemy('boss', bx, by);
}
}
}
// Enemies regenerate 10% max HP every 6 seconds
if (gameTime % 360 === 0 && gameTime > 0) {
for (var i = 0; i < enemies.length; i++) {
var e = enemies[i];
var regen = Math.floor(e.maxHp * 0.1);
e.hp = Math.min(e.hp + regen, e.maxHp);
}
}
// Enemies' max HP increases by 4% every 30 seconds
if (gameTime % 1800 === 0 && gameTime > 0) {
for (var i = 0; i < enemies.length; i++) {
var e = enemies[i];
var oldMax = e.maxHp;
e.maxHp = Math.floor(e.maxHp * 1.04);
// Increase current HP by same ratio
e.hp = Math.floor(e.hp * (e.maxHp / oldMax));
// Don't let HP drop below 1
if (e.hp < 1) e.hp = 1;
}
}
// Update enemies
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
var dx = enemy.x - player.x;
var dy = enemy.y - player.y;
var distSq = dx * dx + dy * dy;
// 150 piksel mesafe için distSq <= 22500 kullanıyoruz.
if (distSq <= 22500) {
if (enemy.lastHitTime === undefined || gameTime - enemy.lastHitTime >= 60) {
player.takeDamage(enemy.damage);
enemy.lastHitTime = gameTime;
}
}
}
// Update exp orbs
for (var i = expOrbs.length - 1; i >= 0; i--) {
var orb = expOrbs[i];
var dx = orb.x - player.x;
var dy = orb.y - player.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < player.pickupRange) {
orb.magnetSpeed = 10;
}
if (orb.intersects(player)) {
player.gainExp(orb.value);
orb.destroy();
expOrbs.splice(i, 1);
LK.getSound('pickup').play();
}
}
// Spawn pickups randomly
if (gameTime - lastPickupSpawn > 1800 && Math.random() < 0.1) {
lastPickupSpawn = gameTime;
var pickup;
var angle = Math.random() * Math.PI * 2;
var distance = 300 + Math.random() * 500;
var pickupX = player.x + Math.cos(angle) * distance;
var pickupY = player.y + Math.sin(angle) * distance;
var randVal = Math.random();
if (randVal < 0.4) {
pickup = new Bomb();
} else if (randVal < 0.8) {
pickup = new Magnet();
} else {
pickup = new ChickenLeg();
}
pickup.x = pickupX;
pickup.y = pickupY;
pickups.push(pickup);
gameContainer.addChild(pickup);
}
// Update pickups
for (var i = pickups.length - 1; i >= 0; i--) {
var pickup = pickups[i];
if (!pickup.active) {
pickups.splice(i, 1);
}
}
};
// Initial spawn
spawnWave();
// Start background music at game start
LK.playMusic('backGroundMusic'); ===================================================================
--- original.js
+++ change.js
@@ -1457,9 +1457,9 @@
joystickDragOffsetX = 0;
joystickDragOffsetY = 0;
};
// Track best survival time
-var bestSurvivalTime = parseInt(storage.getItem('bestTime') || "0", 10);
+var bestSurvivalTime = parseInt(storage.get('bestTime') || "0", 10);
var showBestTimeText = null;
// Game update
game.update = function () {
if (skillSelectionActive) {
Survivor.io style 2D sword swing effect made by HABBY PTE. LTD.. In-Game asset. 2d. High contrast. No shadows. It should only have a slash effect, no swords. The slash effect should also be in the shape of a half moon.
Survivor.io style 2D round soccer ball made by HABBY PTE. LTD.. In-Game asset. 2d. High contrast. No shadows
A 2D Survivor.io style lightning strike from a cloud in the sky to the ground, made by HABBY PTE. LTD.. In-Game asset. 2d. High contrast. No shadows
A red and blue Survivor.io style 2D U-shaped (with N and S) magnet made by HABBY PTE. LTD.. In-Game asset. 2d. High contrast. No shadows
Survivor.io style 2D shuriken made by HABBY PTE. LTD.. In-Game asset. 2d. High contrast. No shadows
Survivor.io style 2D brick made by HABBY PTE. LTD.. In-Game asset. 2d. High contrast. No shadows
Survivor.io style 2D missile rocket made by HABBY PTE. LTD.
A 2D green radiating circular aura in the Survivor.io style made by HABBY PTE. LTD.. In-Game asset. 2d. High contrast. No shadows
A 2D bomb in the style of Survivor.io, made by HABBY PTE. LTD.. In-Game asset. 2d. High contrast. No shadows
A 2D circular burning effect in Survivor.io style made by HABBY PTE. LTD. (not only the surroundings but also the inside burns) In-Game asset. 2d. High contrast. No shadows
A 2D molotov in the Survivor.io style made by HABBY PTE. LTD.. In-Game asset. 2d. High contrast. No shadows
Survivor.io style 2D greenish exp sphere made by HABBY PTE. LTD. No exp written on it. In-Game asset. 2d. High contrast. No shadows
Survivor.io style 2D half-moon orange boomerang made by HABBY PTE. LTD. In-Game asset. 2d. High contrast. No shadows
Survivor.io style 2D 1 chicken leg.. In-Game asset. 2d. High contrast. No shadows
2D survivor.io game style atomic boom effect front view. No text written on it.
2D. Ranged zombie. attacks with poisonous saliva. In-Game asset. 2d. High contrast. No shadows
2D. Child (small) zombie. He has a small saw in his hand.. In-Game asset. 2d. High contrast. No shadows
2D. Fat zombie. His hands are too big.. In-Game asset. 2d. High contrast. No shadows
Poisonous green circular saliva. 2D. Top View.. In-Game asset. 2d. High contrast. No shadows
Small green claw slash effect. 2D. Top View.. In-Game asset. 2d. High contrast. No shadows
Giant boss angry reddish zombie. 2D.. In-Game asset. 2d. High contrast. No shadows
Small saw slash effect. 2D. Top View.. In-Game asset. 2d. High contrast. No shadows
Big red fist slash effect. 2D. Top View.. In-Game asset. 2d. High contrast. No shadows
Kanlı kemik 2D. Top View.. In-Game asset. 2d. High contrast. No shadows
2D character that looks like a prophet and holds a holy book in his hand.. In-Game asset. 2d. High contrast. No shadows
A background image (wallpaper) representing an old prophet-like man with white hair and beard, wearing a priest's robe (hooded) and holding a holy book (christianity, cross) in his hand, fighting against zombies.. In-Game asset. 2d. High contrast. No shadows
Zombie flesh and bone themed 2D cardboard hollow (without text) horizontal rectangular button.. In-Game asset. 2d. High contrast. No shadows
2D. Healer zombie. Like a female zombie in a healer costume.. In-Game asset. 2d. High contrast. No shadows
2D. Brain illustrated healing potion.. In-Game asset. 2d. High contrast. No shadows
A healing blood pool with circular zombie brain and bone particles. Green + (healing) symbols on top. 2D.. In-Game asset. 2d. High contrast. No shadows
2D. Survivor.io game style skill card. No text written on it. No symbols on it. Just the blank card. Green.. In-Game asset. 2d. High contrast. No shadows
2D. Cartoon. The rise of the zombie ghost spirit from the ground.. In-Game asset. 2d. High contrast. No shadows
levelup
Sound effect
hit
Sound effect
rocketBoom
Sound effect
pickup
Sound effect
backGroundMusic
Music
death
Sound effect
damageTaken
Sound effect
mainMenuMusic
Music
deathScreenMusic
Music
swordSoundEffect
Sound effect
bumerangSoundEffect
Sound effect
brickSoundEffect
Sound effect
lightningSoundEffect
Sound effect
ballSoundEffect
Sound effect
rocketSoundEffect
Sound effect
auraSoundEffect
Sound effect
molotovSoundEffect
Sound effect
molotovBoom
Sound effect
introSpeech
Sound effect
bombBoomSound
Sound effect