User prompt
Please fix the bug: 'ReferenceError: Can't find variable: Explosion' in or related to this line: 'var explosion = new Explosion();' Line Number: 3025
User prompt
Please fix the bug: 'ReferenceError: Can't find variable: Explosion' in or related to this line: 'var explosion = new Explosion();' Line Number: 3025
User prompt
Please fix the bug: 'ReferenceError: Can't find variable: Explosion' in or related to this line: 'var explosion = new Explosion();' Line Number: 3025
User prompt
Please fix the bug: 'Script error.' in or related to this line: 'var fireball = new Fireball();' Line Number: 1782
User prompt
Please fix the bug: 'Timeout.tick error: Can't find variable: Enemy' in or related to this line: 'enemy = new Enemy();' Line Number: 2186
User prompt
Please fix the bug: 'Can't find variable: Wizard' in or related to this line: 'var wizard = new Wizard();' Line Number: 80
User prompt
Please fix the bug: 'Can't find variable: Wizard' in or related to this line: 'var wizard = new Wizard();' Line Number: 80
User prompt
Add fireboss all properties like boss and use fireboss asset spawn this boss at score 30
User prompt
Please fix the bug: 'ReferenceError: Can't find variable: boss' in or related to this line: 'if (boss && !boss.destroyed) {' Line Number: 3543
User prompt
Please fix the bug: 'Timeout.tick error: Can't find variable: boss' in or related to this line: 'if (boss && !boss.destroyed) {' Line Number: 2721
User prompt
Add one more boss which fireboss use bossfire asset and firebossbullet for bullet. All properties like normal boss
User prompt
Please fix the bug: 'Can't find variable: Wizard' in or related to this line: 'var wizard = new Wizard();' Line Number: 80
User prompt
Please fix the bug: 'Can't find variable: Wizard' in or related to this line: 'var wizard = new Wizard();' Line Number: 80
User prompt
Spawn fireboss at score 5
User prompt
Add one more boss which fireboss use bossfire asset and firebossbullet for bullet. All properties like normal boss
User prompt
Bossun gelme seviyesini 5 yerne 50ye çıkar
User prompt
Eğer dört saniyelik yavaşlatma uygulanıyorsa yeni gelen düşmanlarında hızı aynı şekilde düşürülsün
User prompt
4 saniye boyunca yavaşlatma uygula
User prompt
Boss öldüğünde timer seçildiğinde 10 saniyede bir 2 saniye boyunda gelen düşmanların hareket hızını üçte bir azalt
User prompt
Yarı yarıya yavaşlatalım
User prompt
Büyüyüp küçülme efektini 3te 1 daha yavaş yap
User prompt
Firecircle assetini y ekseninde 90 derece yuksrıya doğru döndür ama sadece asseti yani görünüşü
User prompt
Firecircle assetini çevir
User prompt
Firecircle assetinin oyundaki duruşunu 90 derece döndür
User prompt
Rotate firecircle asset 90 angle
/****
* Plugins
****/
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
// Boss class: fires directly at wizard, uses boss asset and BossBullet
var Boss = Container.expand(function () {
var self = Container.call(this);
var bossSprite = self.attachAsset('boss', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 30;
self.lastX = 0;
self.lastY = 0;
self.fireCooldown = 0;
self.fireInterval = 200; // frames (~3.3s at 60fps) - boss fires even less often
self.speed = 6;
self.state = "enter"; // "enter" or "fight"
self.update = function () {
// Enter from top, then stop and start fighting
if (self.state === "enter") {
self.y += self.speed;
if (self.y >= 400) {
self.y = 400;
self.state = "fight";
// Initialize orbit parameters
self.orbitAngle = 0;
self.orbitRadius = 850; // Even wider orbit
self.orbitSpeed = 0.006 + Math.random() * 0.003; // 3te1 daha yavaş (1/3 speed)
self.orbitDirection = Math.random() < 0.5 ? 1 : -1; // random direction
self.orbitDirChangeTimer = 0; // For smooth direction change
self.orbitDirTarget = self.orbitDirection;
}
} else if (self.state === "fight") {
// Orbit around wizard
if (typeof self.orbitAngle === "undefined") self.orbitAngle = 0;
if (typeof self.orbitRadius === "undefined") self.orbitRadius = 650; // Match new default
if (typeof self.orbitSpeed === "undefined") self.orbitSpeed = 0.012 + Math.random() * 0.008; // Match new default
if (typeof self.orbitDirection === "undefined") self.orbitDirection = 1;
// Smoothly change orbit direction every 2-4 seconds
if (typeof self.orbitDirChangeTimer === "undefined") self.orbitDirChangeTimer = 0;
if (typeof self.orbitDirTarget === "undefined") self.orbitDirTarget = self.orbitDirection;
self.orbitDirChangeTimer--;
if (self.orbitDirChangeTimer <= 0) {
// Pick a new direction: -1, 1, or a random value in between for smoothness
var newTarget = Math.random() < 0.5 ? -1 : 1;
// Occasionally pick a value in between for smoothness
if (Math.random() < 0.4) newTarget = (Math.random() - 0.5) * 2;
self.orbitDirTarget = newTarget;
self.orbitDirChangeTimer = 120 + Math.floor(Math.random() * 120); // 2-4 seconds
}
// Smoothly interpolate orbitDirection toward orbitDirTarget
self.orbitDirection += (self.orbitDirTarget - self.orbitDirection) * 0.04;
// Update orbit angle
self.orbitAngle += self.orbitSpeed * self.orbitDirection;
// Orbit center is wizard's current position
var centerX = wizard.x;
var centerY = wizard.y;
// Calculate boss position on orbit
self.x = centerX + Math.cos(self.orbitAngle) * self.orbitRadius;
self.y = centerY + Math.sin(self.orbitAngle) * self.orbitRadius;
// Always face wizard (for firing), but keep boss sprite visually fixed
var dx = wizard.x - self.x;
var dy = wizard.y - self.y;
var angle = Math.atan2(dy, dx);
// Do NOT rotate boss sprite visually; keep it fixed
// (But still use 'angle' for boss bullet firing below)
// Fire at wizard every interval
self.fireCooldown--;
if (self.fireCooldown <= 0) {
// Fire BossBullet at wizard
var bullet = new BossBullet();
bullet.x = self.x;
bullet.y = self.y;
// Calculate direction to wizard
var dx = wizard.x - self.x;
var dy = wizard.y - self.y;
var len = Math.sqrt(dx * dx + dy * dy);
var speed = 5; // 300 units/sec at 60fps
if (len > 0) {
bullet.vx = dx / len * speed;
bullet.vy = dy / len * speed;
}
// Rotate bullet sprite to face direction
if (bullet.children && bullet.children.length > 0) {
bullet.children[0].rotation = Math.atan2(bullet.vy, bullet.vx);
}
if (typeof bossBullets !== "undefined") {
bossBullets.push(bullet);
game.addChild(bullet);
}
self.fireCooldown = self.fireInterval;
}
}
// Animate boss (pulse)
var t = LK.ticks || Date.now();
var scale = 1 + 0.18 * Math.sin((t + self.x + self.y) * 0.06);
if (self.children && self.children.length > 0) {
self.children[0].scale.x = scale;
self.children[0].scale.y = scale;
}
self.lastX = self.x;
self.lastY = self.y;
};
return self;
});
// BossBullet: fired by boss, moves toward wizard, 2 health, can be destroyed by fireballs
var BossBullet = Container.expand(function () {
var self = Container.call(this);
var bulletSprite = self.attachAsset('bossbullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.vx = 0;
self.vy = 0;
self.health = 2;
self.lastX = 0;
self.lastY = 0;
self.lastWasIntersecting = false;
self.update = function () {
self.x += self.vx;
self.y += self.vy;
// Remove if off screen
if (self.x < -120 || self.x > 2048 + 120 || self.y < -120 || self.y > 2732 + 120) {
self.destroy();
}
self.lastX = self.x;
self.lastY = self.y;
};
return self;
});
// Game update: update wizard, fireballs, enemies, handle collisions, and scoring
// Coin class: represents coins dropped by enemies when destroyed
var Coin = Container.expand(function () {
var self = Container.call(this);
// Create a gold coin visual (using a yellow circle)
var coinSprite = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
// Coin movement properties
self.vx = 0;
self.vy = 0;
self.gravity = 0;
self.collected = false;
// Track last position for event triggers
self.lastX = 0;
self.lastY = 0;
self.lastWasIntersecting = false;
self.update = function () {
// No gravity or bounce logic needed
// Remove coin if it leaves the screen horizontally
if (self.x < -50 || self.x > 2048 + 50) {
self.destroy();
}
// Pulsate slightly for visual effect
var t = LK.ticks || Date.now();
var scale = 1 + 0.1 * Math.sin(t * 0.1);
if (self.children && self.children.length > 0) {
self.children[0].scale.x = scale;
self.children[0].scale.y = scale;
}
self.lastX = self.x;
self.lastY = self.y;
};
return self;
});
// Enemy class: represents an enemy that moves toward the wizard
var Enemy = Container.expand(function () {
var self = Container.call(this);
// Attach a unique enemy asset (pixel blue monster)
var enemySprite = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
// Enemy speed and direction
self.vx = 0;
self.vy = 0;
// Track last position for event triggers
self.lastX = 0;
self.lastY = 0;
self.health = 1; // Enemy1: 1 hit to kill
self.type = 1;
self.update = function () {
self.x += self.vx;
self.y += self.vy;
// Pulsate scale for movement effect
var t = LK.ticks || Date.now(); // fallback for safety
var scale = 1 + 0.15 * Math.sin((t + self.x + self.y) * 0.05);
if (self.children && self.children.length > 0) {
self.children[0].scale.x = scale;
self.children[0].scale.y = scale;
}
// Remove enemy if it leaves the screen
if (self.x < -100 || self.x > 2048 + 100 || self.y < -100 || self.y > 2732 + 100) {
self.destroy();
}
self.lastX = self.x;
self.lastY = self.y;
};
return self;
});
// Enemy2: needs 2 fireballs to die
var Enemy2 = Container.expand(function () {
var self = Container.call(this);
var enemySprite = self.attachAsset('enemy2', {
anchorX: 0.5,
anchorY: 0.5
});
self.vx = 0;
self.vy = 0;
self.lastX = 0;
self.lastY = 0;
self.health = 2;
self.type = 2;
self.update = function () {
self.x += self.vx;
self.y += self.vy;
var t = LK.ticks || Date.now();
var scale = 1 + 0.18 * Math.sin((t + self.x + self.y) * 0.06);
if (self.children && self.children.length > 0) {
self.children[0].scale.x = scale;
self.children[0].scale.y = scale;
}
if (self.x < -100 || self.x > 2048 + 100 || self.y < -100 || self.y > 2732 + 100) {
self.destroy();
}
self.lastX = self.x;
self.lastY = self.y;
};
return self;
});
// Enemy3: needs 3 fireballs to die
var Enemy3 = Container.expand(function () {
var self = Container.call(this);
var enemySprite = self.attachAsset('enemy3', {
anchorX: 0.5,
anchorY: 0.5
});
self.vx = 0;
self.vy = 0;
self.lastX = 0;
self.lastY = 0;
self.health = 3;
self.type = 3;
self.update = function () {
self.x += self.vx;
self.y += self.vy;
var t = LK.ticks || Date.now();
var scale = 1 + 0.22 * Math.sin((t + self.x + self.y) * 0.07);
if (self.children && self.children.length > 0) {
self.children[0].scale.x = scale;
self.children[0].scale.y = scale;
}
if (self.x < -100 || self.x > 2048 + 100 || self.y < -100 || self.y > 2732 + 100) {
self.destroy();
}
self.lastX = self.x;
self.lastY = self.y;
};
return self;
});
// Enemy4: needs 4 fireballs to die
var Enemy4 = Container.expand(function () {
var self = Container.call(this);
var enemySprite = self.attachAsset('enemy4', {
anchorX: 0.5,
anchorY: 0.5
});
self.vx = 0;
self.vy = 0;
self.lastX = 0;
self.lastY = 0;
self.health = 4;
self.type = 4;
self.update = function () {
self.x += self.vx;
self.y += self.vy;
var t = LK.ticks || Date.now();
var scale = 1 + 0.26 * Math.sin((t + self.x + self.y) * 0.08);
if (self.children && self.children.length > 0) {
self.children[0].scale.x = scale;
self.children[0].scale.y = scale;
}
if (self.x < -100 || self.x > 2048 + 100 || self.y < -100 || self.y > 2732 + 100) {
self.destroy();
}
self.lastX = self.x;
self.lastY = self.y;
};
return self;
});
// Enemy5: Goblin, appears at score 5, moves freely but never enters the center area
var Enemy5 = Container.expand(function () {
var self = Container.call(this);
var goblinSprite = self.attachAsset('goblin', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 20;
self.type = 5;
self.lastX = 0;
self.lastY = 0;
// --- Free movement variables ---
self.vx = (Math.random() - 0.5) * 13 + (Math.random() < 0.5 ? -7 : 7); // random speed, avoid 0
self.vy = (Math.random() - 0.5) * 13 + (Math.random() < 0.5 ? -7 : 7);
self.changeDirCooldown = 0;
// Start at a random edge
var edge = Math.floor(Math.random() * 4);
if (edge === 0) {
// top
self.x = Math.random() * 2048;
self.y = -90;
} else if (edge === 1) {
// bottom
self.x = Math.random() * 2048;
self.y = 2732 + 90;
} else if (edge === 2) {
// left
self.x = -90;
self.y = Math.random() * 2732;
} else {
// right
self.x = 2048 + 90;
self.y = Math.random() * 2732;
}
// --- Center area to avoid ---
var centerAreaX = 2048 / 2;
var centerAreaY = 2732 / 2;
var centerRadius = 420; // px, forbidden zone
// --- Timed self-destruction after 15 seconds ---
self.spawnTick = typeof LK.ticks !== "undefined" ? LK.ticks : 0;
self.smokeShown = false;
self.update = function () {
// Move freely
self.x += self.vx;
self.y += self.vy;
// Bounce off screen edges
if (self.x < 0 + 90 && self.vx < 0) self.vx = Math.abs(self.vx);
if (self.x > 2048 - 90 && self.vx > 0) self.vx = -Math.abs(self.vx);
if (self.y < 0 + 90 && self.vy < 0) self.vy = Math.abs(self.vy);
if (self.y > 2732 - 90 && self.vy > 0) self.vy = -Math.abs(self.vy);
// Never enter the center forbidden area
var dx = self.x - centerAreaX;
var dy = self.y - centerAreaY;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < centerRadius) {
// Push goblin out of the center area
var angle = Math.atan2(dy, dx);
self.x = centerAreaX + Math.cos(angle) * (centerRadius + 2);
self.y = centerAreaY + Math.sin(angle) * (centerRadius + 2);
// Bounce away
self.vx = Math.cos(angle) * (8 + Math.random() * 5);
self.vy = Math.sin(angle) * (8 + Math.random() * 5);
}
// Occasionally change direction randomly
self.changeDirCooldown--;
if (self.changeDirCooldown <= 0) {
var angle = Math.atan2(self.vy, self.vx) + (Math.random() - 0.5) * 0.7;
var speed = 7 + Math.random() * 6;
self.vx = Math.cos(angle) * speed;
self.vy = Math.sin(angle) * speed;
self.changeDirCooldown = 60 + Math.floor(Math.random() * 60); // 1-2 seconds
}
// Animate goblin (pulse)
var t = LK.ticks || Date.now();
var scale = 1 + 0.18 * Math.sin((t + self.x + self.y) * 0.09);
if (self.children && self.children.length > 0) {
self.children[0].scale.x = scale;
self.children[0].scale.y = scale;
}
// --- Timed self-destruction after 15 seconds ---
if (!self.smokeShown && typeof LK.ticks !== "undefined" && LK.ticks - self.spawnTick >= 900) {
// 15s at 60fps
// Show smoke at goblin's position
var smoke = LK.getAsset('Smoke', {
anchorX: 0.5,
anchorY: 0.5,
x: self.x,
y: self.y,
scaleX: 1.0,
scaleY: 1.0,
alpha: 1
});
game.addChild(smoke);
// Animate smoke: fade out and scale up over 0.7s (42 frames)
(function (smokeObj) {
var frames = 42,
frame = 0;
smokeObj.update = function () {
frame++;
smokeObj.scale.x = 1.0 + 0.5 * (frame / frames);
smokeObj.scale.y = 1.0 + 0.5 * (frame / frames);
smokeObj.alpha = 1 - frame / frames;
if (frame >= frames) {
smokeObj.destroy();
}
};
})(smoke);
self.smokeShown = true;
// Mark goblin as permanently killed (so it never respawns)
enemy5EverKilled = true;
// Remove goblin from game
self.destroy();
// Remove from enemies array in game.update (handled by main loop)
// enemy5 reference will be cleared in main loop on destroy
return;
}
self.lastX = self.x;
self.lastY = self.y;
};
return self;
});
// Enemy6: appears at score 20, uses enemy6 asset, 2 health
var Enemy6 = Container.expand(function () {
var self = Container.call(this);
var enemySprite = self.attachAsset('enemy6', {
anchorX: 0.5,
anchorY: 0.5
});
self.vx = 0;
self.vy = 0;
self.lastX = 0;
self.lastY = 0;
self.health = 2;
self.type = 6;
self.update = function () {
self.x += self.vx;
self.y += self.vy;
var t = LK.ticks || Date.now();
var scale = 1 + 0.18 * Math.sin((t + self.x + self.y) * 0.06);
if (self.children && self.children.length > 0) {
self.children[0].scale.x = scale;
self.children[0].scale.y = scale;
}
if (self.x < -100 || self.x > 2048 + 100 || self.y < -100 || self.y > 2732 + 100) {
self.destroy();
}
self.lastX = self.x;
self.lastY = self.y;
};
return self;
});
// Explosion class: shows a quick explosion effect at (x, y)
var Explosion = Container.expand(function () {
var self = Container.call(this);
var sprite = self.attachAsset('explosion', {
anchorX: 0.5,
anchorY: 0.5
});
// Initial scale and alpha
sprite.scale.x = 0.5;
sprite.scale.y = 0.5;
sprite.alpha = 1;
// Animate explosion: grow and fade out
var duration = 18; // frames (~0.3s)
var frame = 0;
self.update = function () {
frame++;
// Grow and fade
var progress = frame / duration;
sprite.scale.x = 0.5 + 1.2 * progress;
sprite.scale.y = 0.5 + 1.2 * progress;
sprite.alpha = 1 - progress;
if (frame >= duration) {
self.destroy();
}
};
return self;
});
// FireCircle: orbiting fire damage area after boss reward
var FireCircle = Container.expand(function () {
var self = Container.call(this);
// Attach firecircle asset
var sprite = self.attachAsset('firecircle', {
anchorX: 0.5,
anchorY: 0.5,
rotation: -Math.PI / 2 // 90 derece yukarıya döndür (saat yönünün tersine)
});
// Orbit parameters
self.orbitRadius = 850;
self.orbitAngle = 0;
self.orbitSpeed = 0.009; // Yarı yarıya yavaşlatıldı (half speed)
self.centerX = 2048 / 2;
self.centerY = 2732 / 2;
self.damage = 2; // FireCircle now deals 2 damage per hit
self.enemiesHit = {}; // Track which enemies have been hit this frame
self.update = function () {
// Orbit around wizard (or last known wizard position)
if (typeof wizard !== "undefined" && wizard && !wizard.destroyed) {
self.centerX = wizard.x;
self.centerY = wizard.y;
}
self.orbitAngle += self.orbitSpeed;
self.x = self.centerX + Math.cos(self.orbitAngle) * self.orbitRadius;
self.y = self.centerY + Math.sin(self.orbitAngle) * self.orbitRadius;
// Animate (pulse + spin)
var t = LK.ticks || Date.now();
// Make pulse 3 times slower: divide frequency by 3 (multiply period by 3)
var scale = 1 + 0.08 * Math.sin((t + self.x + self.y) * (0.09 / 3));
if (self.children && self.children.length > 0) {
self.children[0].scale.x = scale;
self.children[0].scale.y = scale;
// Add 360-degree spin effect (rotate asset as it orbits)
self.children[0].rotation = self.orbitAngle;
}
// Damage enemies that intersect, every frame (permanent, not once per activation)
if (typeof enemies !== "undefined") {
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
if (!enemy || enemy.destroyed) continue;
// Assign a unique id if not present
if (typeof enemy._fireCircleId === "undefined") {
enemy._fireCircleId = Math.random().toString(36).substr(2, 9) + Date.now();
}
// Only damage once per frame
if (!self.enemiesHit[enemy._fireCircleId] && self.intersects(enemy)) {
// If enemy has 2 or 1 health, instantly kill
if (enemy.health === 2 || enemy.health === 1) {
enemy.health = 0;
} else {
enemy.health -= self.damage;
}
self.enemiesHit[enemy._fireCircleId] = true;
// Flash enemy for feedback
if (enemy.children && enemy.children.length > 0) {
LK.effects.flashObject(enemy.children[0], 0xff6600, 200);
}
// If enemy dies, handle in main game.update
}
}
}
// Reset hit tracking for next frame
self.enemiesHit = {};
};
return self;
});
// Fireball class: represents a fireball shot by the wizard
var Fireball = Container.expand(function () {
var self = Container.call(this);
// Attach fireball asset (pixel fireball)
var fireballSprite = self.attachAsset('fireball', {
anchorX: 0.5,
anchorY: 0.5
});
// Fireball speed and direction
self.vx = 0;
self.vy = 0;
// Track last position for event triggers
self.lastX = 0;
self.lastY = 0;
self.update = function () {
self.x += self.vx;
self.y += self.vy;
// Remove fireball if it leaves the screen
if (self.x < -100 || self.x > 2048 + 100 || self.y < -100 || self.y > 2732 + 100) {
self.destroy();
}
self.lastX = self.x;
self.lastY = self.y;
};
return self;
});
// Healthpack class: dropped by Enemy6, restores 2 wizard health when collected
var Healthpack = Container.expand(function () {
var self = Container.call(this);
// Attach healthpack asset
var sprite = self.attachAsset('healthpack', {
anchorX: 0.5,
anchorY: 0.5
});
// Track last position for event triggers
self.lastX = 0;
self.lastY = 0;
self.lastWasIntersecting = false;
self.update = function () {
// Move toward wizard like coin
if (typeof wizard !== "undefined" && wizard) {
var dx = wizard.x - self.x;
var dy = wizard.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
var speed = 22;
if (dist > 1) {
self.x += dx / dist * Math.min(speed, dist);
self.y += dy / dist * Math.min(speed, dist);
} else {
self.x = wizard.x;
self.y = wizard.y;
}
}
// Pulsate for effect
var t = LK.ticks || Date.now();
var scale = 1 + 0.12 * Math.sin((t + self.x + self.y) * 0.13);
if (self.children && self.children.length > 0) {
self.children[0].scale.x = scale;
self.children[0].scale.y = scale;
}
self.lastX = self.x;
self.lastY = self.y;
};
return self;
});
// Wizard class: represents the player character
var Wizard = Container.expand(function () {
var self = Container.call(this);
// Attach wizard asset (blue hat, pixel style)
var wizardSprite = self.attachAsset('wizard', {
anchorX: 0.5,
anchorY: 0.5
});
// Track last position for event triggers
self.lastX = 0;
self.lastY = 0;
// Update method (called every tick)
self.update = function () {
// No movement logic here; wizard is moved by mouse/touch
self.lastX = self.x;
self.lastY = self.y;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Explosion asset for enemy death effect
;
// Add background image to the game scene
var background = LK.getAsset('background', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
width: 2048,
height: 2732
});
game.addChild(background);
// --- Game Code for Pixel Wizard: Blue Hat Adventure ---
// Create wizard instance and add to game
var wizard = new Wizard();
game.addChild(wizard);
// Center wizard on screen at start
wizard.x = 2048 / 2;
wizard.y = 2732 / 2;
// --- START & UPGRADE BUTTON UI LOGIC ---
var gameStarted = false;
// UI container for start and upgrade buttons
var startUiContainer = new Container();
// Create start button asset (simple box with text)
var startButtonWidth = 420;
var startButtonHeight = 140;
var startButton = new Container();
var startButtonBg = LK.getAsset('background', {
anchorX: 0.5,
anchorY: 0.5,
width: startButtonWidth,
height: startButtonHeight
});
startButtonBg.alpha = 0.92;
startButton.addChild(startButtonBg);
var startButtonText = new Text2("START GAME", {
size: 220,
fill: "#fff"
});
startButtonText.anchor.set(0.5, 0.5);
startButtonText.x = 0;
startButtonText.y = -120;
startButton.addChild(startButtonText);
// Create upgrade button below start button
var upgradeButtonWidth = 420;
var upgradeButtonHeight = 110;
var upgradeButton = new Container();
var upgradeButtonBg = LK.getAsset('background', {
anchorX: 0.5,
anchorY: 0.5,
width: upgradeButtonWidth,
height: upgradeButtonHeight
});
upgradeButtonBg.alpha = 0.92;
upgradeButton.addChild(upgradeButtonBg);
var upgradeButtonText = new Text2("UPGRADE", {
size: 110,
// Half of START GAME (220)
fill: "#fff"
});
upgradeButtonText.anchor.set(0.5, 0.5);
upgradeButtonText.x = 0;
upgradeButtonText.y = 0;
upgradeButton.addChild(upgradeButtonText);
// Position start, upgrade, and shop buttons in the UI container
startButton.x = 0;
startButton.y = -400; //{36} // Moved much higher
upgradeButton.x = 0;
upgradeButton.y = startButton.y + startButtonHeight / 2 + 55 + upgradeButtonHeight / 2; //{38} // Increased spacing by 15px
// --- SHOP BUTTON UI LOGIC ---
var shopButtonWidth = 420;
var shopButtonHeight = 110;
var shopButton = new Container();
var shopButtonBg = LK.getAsset('background', {
anchorX: 0.5,
anchorY: 0.5,
width: shopButtonWidth,
height: shopButtonHeight
});
shopButtonBg.alpha = 0.92;
shopButton.addChild(shopButtonBg);
var shopButtonText = new Text2("SHOP", {
size: 110,
fill: "#fff"
});
shopButtonText.anchor.set(0.5, 0.5);
shopButtonText.x = 0;
shopButtonText.y = 0;
shopButton.addChild(shopButtonText);
// Position shop button below upgrade button
shopButton.x = 0;
shopButton.y = upgradeButton.y + upgradeButtonHeight / 2 + 40 + shopButtonHeight / 2;
// Add all three buttons to the UI container
startUiContainer.addChild(startButton);
startUiContainer.addChild(upgradeButton);
startUiContainer.addChild(shopButton);
// --- RESET BUTTON UI LOGIC ---
var resetButtonWidth = 420;
var resetButtonHeight = 110;
var resetButton = new Container();
var resetButtonBg = LK.getAsset('background', {
anchorX: 0.5,
anchorY: 0.5,
width: resetButtonWidth,
height: resetButtonHeight
});
resetButtonBg.alpha = 0.92;
resetButton.addChild(resetButtonBg);
var resetButtonText = new Text2("RESET", {
size: 110,
fill: "#fff"
});
resetButtonText.anchor.set(0.5, 0.5);
resetButtonText.x = 0;
resetButtonText.y = 0;
resetButton.addChild(resetButtonText);
// Position reset button below shop button
resetButton.x = 0;
resetButton.y = shopButton.y + shopButtonHeight / 2 + 40 + resetButtonHeight / 2;
startUiContainer.addChild(resetButton);
// --- RESET POPUP LOGIC ---
var resetPopup = null;
function showResetPopup() {
if (resetPopup && !resetPopup.destroyed) return;
resetPopup = new Container();
// Popup background
var popupW = 900;
var popupH = 600;
var popupBg = LK.getAsset('background', {
anchorX: 0.5,
anchorY: 0.5,
width: popupW,
height: popupH
});
popupBg.alpha = 0.98;
resetPopup.addChild(popupBg);
// Popup text
var popupText = new Text2("Are you sure you want to reset all progress?", {
size: 80,
fill: "#fff"
});
popupText.anchor.set(0.5, 0.5);
popupText.x = 0;
popupText.y = -100;
resetPopup.addChild(popupText);
// Yes button
var yesBtn = new Container();
var yesBtnBg = LK.getAsset('background', {
anchorX: 0.5,
anchorY: 0.5,
width: 320,
height: 120
});
yesBtnBg.alpha = 0.95;
yesBtn.addChild(yesBtnBg);
var yesBtnText = new Text2("YES", {
size: 90,
fill: 0x2ECC40
});
yesBtnText.anchor.set(0.5, 0.5);
yesBtnText.x = 0;
yesBtnText.y = 0;
yesBtn.addChild(yesBtnText);
yesBtn.x = -180;
yesBtn.y = 120;
// No button
var noBtn = new Container();
var noBtnBg = LK.getAsset('background', {
anchorX: 0.5,
anchorY: 0.5,
width: 320,
height: 120
});
noBtnBg.alpha = 0.95;
noBtn.addChild(noBtnBg);
var noBtnText = new Text2("NO", {
size: 90,
fill: 0xE74C3C
});
noBtnText.anchor.set(0.5, 0.5);
noBtnText.x = 0;
noBtnText.y = 0;
noBtn.addChild(noBtnText);
noBtn.x = 180;
noBtn.y = 120;
// Add buttons to popup
resetPopup.addChild(yesBtn);
resetPopup.addChild(noBtn);
// Center popup
resetPopup.x = 2048 / 2;
resetPopup.y = 2732 / 2;
game.addChild(resetPopup);
// Yes: reset all progress and reload game state
yesBtn.down = function () {
// Clear all persistent storage
for (var key in storage) {
if (storage.hasOwnProperty(key)) {
delete storage[key];
}
}
// Remove all weapon upgrades from storage
for (var key in storage) {
if (storage.hasOwnProperty(key) && key.indexOf("weaponUpgrades_") === 0) {
delete storage[key];
}
}
// Also clear all in-memory weapon upgrades for all weapons and set to first stage
if (typeof weaponUpgradeDefaults !== "undefined") {
var weaponAssets = ["wizard", "submachine", "MP5", "shuriken", "shotgun", "minigun", "Lasergun"];
for (var i = 0; i < weaponAssets.length; i++) {
var key = getWeaponUpgradeKey(weaponAssets[i]);
// Set all upgrades to first stage (level 0, cost default, health 5, damage 1, etc)
var upgrades = {};
for (var k in weaponUpgradeDefaults) upgrades[k] = weaponUpgradeDefaults[k];
storage[key] = upgrades;
}
}
// Optionally, force reload by reloading the page, but here we just reset all variables and UI
// Remove popup
if (resetPopup && !resetPopup.destroyed) {
resetPopup.destroy();
resetPopup = null;
}
// Remove start UI if present
if (startUiContainer && !startUiContainer.destroyed) {
startUiContainer.destroy();
}
// Remove all enemies, fireballs, coins
for (var i = enemies.length - 1; i >= 0; i--) {
if (enemies[i] && !enemies[i].destroyed) enemies[i].destroy();
enemies.splice(i, 1);
}
for (var i = fireballs.length - 1; i >= 0; i--) {
if (fireballs[i] && !fireballs[i].destroyed) fireballs[i].destroy();
fireballs.splice(i, 1);
}
for (var i = coins.length - 1; i >= 0; i--) {
if (coins[i] && !coins[i].destroyed) coins[i].destroy();
coins.splice(i, 1);
}
// Reset all progress variables
score = 0;
coinCount = 0;
storage.coinCount = 0;
speedUpgradeLevel = 0;
speedUpgradeCost = 50;
damageUpgradeLevel = 0;
damageUpgradeCost = 60;
healthUpgradeLevel = 0;
healthUpgradeCost = 25;
maxWizardHealth = 5;
wizardHealth = 5;
fireballDamage = 1;
// Reset shop purchases and upgrades
shopPurchases = {};
storage.shopPurchases = {};
wizardAsset = "wizard";
storage.wizardAsset = "wizard"; // persist default asset
storage.speedUpgradeLevel = 0;
storage.speedUpgradeCost = 50;
storage.damageUpgradeLevel = 0;
storage.damageUpgradeCost = 60;
storage.healthUpgradeLevel = 0;
storage.healthUpgradeCost = 25;
storage.maxWizardHealth = 5;
storage.wizardHealth = 5;
storage.fireballDamage = 1;
// Update UI
scoreText.setText("Score: 0");
coinText.setText("" + coinCount);
// Reset wizard asset to default and ensure only one asset exists
// Remove all children
for (var i = wizard.children.length - 1; i >= 0; i--) {
wizard.removeChild(wizard.children[i]);
}
// Attach new wizard asset as the only sprite
var newSprite = wizard.attachAsset('wizard', {
anchorX: 0.5,
anchorY: 0.5
});
// Reset health bar (no-op)
updateHealthBar();
// Center wizard
wizard.x = 2048 / 2;
wizard.y = 2732 / 2;
if (wizard.children && wizard.children.length > 0) {
wizard.children[0].rotation = Math.PI;
}
// Recreate start UI
startUiContainer = new Container();
startButton = new Container();
startButtonBg = LK.getAsset('background', {
anchorX: 0.5,
anchorY: 0.5,
width: startButtonWidth,
height: startButtonHeight
});
startButtonBg.alpha = 0.92;
startButton.addChild(startButtonBg);
startButtonText = new Text2("START GAME", {
size: 220,
fill: "#fff"
});
startButtonText.anchor.set(0.5, 0.5);
startButtonText.x = 0;
startButtonText.y = -120;
startButton.addChild(startButtonText);
upgradeButton = new Container();
upgradeButtonBg = LK.getAsset('background', {
anchorX: 0.5,
anchorY: 0.5,
width: upgradeButtonWidth,
height: upgradeButtonHeight
});
upgradeButtonBg.alpha = 0.92;
upgradeButton.addChild(upgradeButtonBg);
upgradeButtonText = new Text2("UPGRADE", {
size: 110,
fill: "#fff"
});
upgradeButtonText.anchor.set(0.5, 0.5);
upgradeButtonText.x = 0;
upgradeButtonText.y = 0;
upgradeButton.addChild(upgradeButtonText);
shopButton = new Container();
shopButtonBg = LK.getAsset('background', {
anchorX: 0.5,
anchorY: 0.5,
width: shopButtonWidth,
height: shopButtonHeight
});
shopButtonBg.alpha = 0.92;
shopButton.addChild(shopButtonBg);
shopButtonText = new Text2("SHOP", {
size: 110,
fill: "#fff"
});
shopButtonText.anchor.set(0.5, 0.5);
shopButtonText.x = 0;
shopButtonText.y = 0;
shopButton.addChild(shopButtonText);
// Re-add reset button
resetButton = new Container();
resetButtonBg = LK.getAsset('background', {
anchorX: 0.5,
anchorY: 0.5,
width: resetButtonWidth,
height: resetButtonHeight
});
resetButtonBg.alpha = 0.92;
resetButton.addChild(resetButtonBg);
resetButtonText = new Text2("RESET", {
size: 110,
fill: "#fff"
});
resetButtonText.anchor.set(0.5, 0.5);
resetButtonText.x = 0;
resetButtonText.y = 0;
resetButton.addChild(resetButtonText);
// Position all buttons
startButton.x = 0;
startButton.y = -400;
upgradeButton.x = 0;
upgradeButton.y = startButton.y + startButtonHeight / 2 + 55 + upgradeButtonHeight / 2;
shopButton.x = 0;
shopButton.y = upgradeButton.y + upgradeButtonHeight / 2 + 40 + shopButtonHeight / 2;
resetButton.x = 0;
resetButton.y = shopButton.y + shopButtonHeight / 2 + 40 + resetButtonHeight / 2;
// Add to container
startUiContainer.addChild(startButton);
startUiContainer.addChild(upgradeButton);
startUiContainer.addChild(shopButton);
startUiContainer.addChild(resetButton);
startUiContainer.x = 2048 / 2;
startUiContainer.y = 2732 / 2;
game.addChild(startUiContainer);
// Re-attach handlers
upgradeButton.down = function (x, y, obj) {
if (upgradeWindow && !upgradeWindow.destroyed) return;
showUpgradeWindow();
};
shopButton.down = function (x, y, obj) {
if (shopWindow && !shopWindow.destroyed) return;
showShopWindow();
};
startButton.down = function (x, y, obj) {
if (gameStarted) return;
gameStarted = true;
if (startUiContainer && !startUiContainer.destroyed) {
startUiContainer.destroy();
}
// Remove all enemies, fireballs, coins
for (var i = enemies.length - 1; i >= 0; i--) {
if (enemies[i] && !enemies[i].destroyed) enemies[i].destroy();
enemies.splice(i, 1);
}
for (var i = fireballs.length - 1; i >= 0; i--) {
if (fireballs[i] && !fireballs[i].destroyed) fireballs[i].destroy();
fireballs.splice(i, 1);
}
for (var i = coins.length - 1; i >= 0; i--) {
if (coins[i] && !coins[i].destroyed) coins[i].destroy();
coins.splice(i, 1);
}
score = 0;
scoreText.setText("Score: 0");
coinText.setText("" + coinCount);
wizard.x = 2048 / 2;
wizard.y = 2732 / 2;
if (wizard.children && wizard.children.length > 0) {
wizard.children[0].rotation = Math.PI;
}
// --- Reset magazine system ---
// If minigun is selected, always set to 350 ammo at new game start
if (wizardAsset === "minigun") {
wizardMaxAmmo = applyAmmoUpgradeToMaxAmmo("minigun");
wizardAmmo = wizardMaxAmmo;
tapFireCooldown = 500;
} else if (wizardAsset === "submachine") {
wizardMaxAmmo = applyAmmoUpgradeToMaxAmmo("submachine");
wizardAmmo = wizardMaxAmmo;
tapFireCooldown = 100;
wizardReloadTime = 500;
} else if (wizardAsset === "Lasergun") {
wizardMaxAmmo = applyAmmoUpgradeToMaxAmmo("Lasergun");
wizardAmmo = wizardMaxAmmo;
tapFireCooldown = 300;
} else if (wizardAsset === "shotgun") {
wizardMaxAmmo = applyAmmoUpgradeToMaxAmmo("shotgun");
wizardAmmo = wizardMaxAmmo;
tapFireCooldown = 200;
} else {
wizardMaxAmmo = applyAmmoUpgradeToMaxAmmo(wizardAsset);
wizardAmmo = wizardMaxAmmo;
}
wizardReloading = false;
if (wizardReloadTimeout) {
LK.clearTimeout(wizardReloadTimeout);
wizardReloadTimeout = null;
}
// Health bar is now fixed in the GUI, no need to reposition here
wizardHealth = maxWizardHealth;
updateHealthBar();
game.move = originalGameMove;
game.down = originalGameDown;
game.up = originalGameUp;
};
resetButton.down = function (x, y, obj) {
showResetPopup();
};
// Block input until start is pressed
blockGameInput();
gameStarted = false;
};
// No: close popup
noBtn.down = function () {
if (resetPopup && !resetPopup.destroyed) {
resetPopup.destroy();
resetPopup = null;
}
};
}
// Reset button interaction
resetButton.down = function (x, y, obj) {
showResetPopup();
};
// Position the UI container: horizontally centered, vertically centered
startUiContainer.x = 2048 / 2;
startUiContainer.y = 2732 / 2;
// Add to game
game.addChild(startUiContainer);
// Block input until start is pressed
function blockGameInput() {
game.move = function () {};
game.down = function () {};
game.up = function () {};
isFiring = false;
if (fireInterval) {
LK.clearInterval(fireInterval);
fireInterval = null;
}
}
blockGameInput();
// --- UPGRADE WINDOW LOGIC ---
var upgradeWindow = null;
function showUpgradeWindow() {
if (upgradeWindow && !upgradeWindow.destroyed) return;
upgradeWindow = new Container();
// Window background (main)
var winW = 1200 + 500 - 250,
// Decrease width by 250px
winH = 1100 + 500 + 500; // Increase height by 500px again, width unchanged
var winBg = LK.getAsset('upgradescreen', {
anchorX: 0.5,
anchorY: 0.5,
width: winW,
height: winH
});
winBg.alpha = 0.97;
upgradeWindow.addChild(winBg);
// Title removed: no upgrade window title text
// Button helper with icon
function makeUpgradeBtn(label, y, color, iconAsset, iconColor) {
var btn = new Container();
// No background for speed, power, health, or back buttons
// Icon asset (left side of button)
var icon = null;
if (iconAsset) {
// If this is the health asset, increase its size by 50px
if (iconAsset === 'health') {
icon = LK.getAsset(iconAsset, {
anchorX: 0.5,
anchorY: 0.5,
x: -360,
// 100px more to the left
y: 0,
width: 150,
height: 150
});
} else {
icon = LK.getAsset(iconAsset, {
anchorX: 0.5,
anchorY: 0.5,
x: -360,
// 100px more to the left
y: 0,
scaleX: 1.2,
scaleY: 1.2
});
}
// Remove any filter/overlay in front of the icon (if any exist)
if (icon.filters && icon.filters.length > 0) {
icon.filters = [];
}
btn.addChild(icon);
}
var btnText = new Text2(label, {
size: 100,
fill: "#fff"
});
btnText.anchor.set(0.5, 0.5);
btnText.x = 60;
btnText.y = 0;
btn.addChild(btnText);
btn.x = 0;
btn.y = y;
return btn;
}
// Hız, Hüç, Health, Ammo, Geri buttons with icons and unique colors
var btnSpacing = 220; // Slightly reduced to fit 4 upgrades
var btns = [];
// Use fast, power, background assets for each upgrade (background as health icon)
var btnLabels = [{
label: "SPEED",
iconAsset: 'fast'
}, {
label: "DAMAGE",
iconAsset: 'power'
}, {
label: "HEALTH",
iconAsset: 'health'
}, {
label: "AMMO",
iconAsset: 'ammoupgrade'
}];
for (var i = 0; i < btnLabels.length; i++) {
var btn = makeUpgradeBtn(btnLabels[i].label, -180 + i * btnSpacing, btnLabels[i].color, btnLabels[i].iconAsset, btnLabels[i].iconColor);
upgradeWindow.addChild(btn);
btns.push(btn);
}
// --- SPEED UPGRADE LOGIC (5 seviye, her silah için ayrı ayrı, atış ve mermi hızı) ---
if (typeof speedUpgradeBtnText === "undefined") speedUpgradeBtnText = null;
var upgrades = getWeaponUpgrades(wizardAsset);
speedUpgradeLevel = upgrades.speedUpgradeLevel;
// Set cost to 100 * (level+1) for each upgrade, max 5 upgrades
speedUpgradeCost = speedUpgradeLevel < 5 ? 100 * (speedUpgradeLevel + 1) : "-";
upgrades.speedUpgradeCost = speedUpgradeCost;
btns[0].down = function () {
var upgrades = getWeaponUpgrades(wizardAsset);
// Always set cost to 100 * (level+1) for each upgrade, max 5 upgrades
upgrades.speedUpgradeCost = upgrades.speedUpgradeLevel < 5 ? 100 * (upgrades.speedUpgradeLevel + 1) : "-";
if (coinCount >= upgrades.speedUpgradeCost && upgrades.speedUpgradeLevel < 5) {
coinCount -= upgrades.speedUpgradeCost;
coinText.setText("" + coinCount);
upgrades.speedUpgradeLevel += 1;
// Her seviye için maliyet: 100, 200, 300, 400, 500 coin
upgrades.speedUpgradeCost = upgrades.speedUpgradeLevel < 5 ? 100 * (upgrades.speedUpgradeLevel + 1) : "-";
saveWeaponUpgrades(wizardAsset, upgrades);
speedUpgradeLevel = upgrades.speedUpgradeLevel;
speedUpgradeCost = upgrades.speedUpgradeCost;
// Atış hızı: tapFireCooldown'u azalt (daha hızlı ateş)
// Mermi hızı: shootFireballAt fonksiyonunda kullanılacak
tapFireCooldown = Math.max(80, 850 - speedUpgradeLevel * 140);
// Buton label güncelle
if (speedUpgradeBtnText) {
if (btns[0].coinIcon && btns[0].coinIcon.parent) {
btns[0].coinIcon.parent.removeChild(btns[0].coinIcon);
btns[0].coinIcon = null;
}
if (speedUpgradeLevel < 5) {
speedUpgradeBtnText.setText("SPEED | " + speedUpgradeCost);
var coinAsset = LK.getAsset('coin', {
anchorX: 0.0,
anchorY: 0.5,
scaleX: 0.7,
scaleY: 0.7
});
coinAsset.x = speedUpgradeBtnText.x + speedUpgradeBtnText.width / 2 + coinAsset.width * 0.6;
coinAsset.y = speedUpgradeBtnText.y;
btns[0].addChild(coinAsset);
btns[0].coinIcon = coinAsset;
} else {
speedUpgradeBtnText.setText("SPEED | MAX");
}
}
LK.effects.flashObject(btns[0], 0x2ecc40, 400);
} else if (speedUpgradeLevel >= 5) {
LK.effects.flashObject(btns[0], 0x888888, 400);
} else {
LK.effects.flashObject(coinText, 0xe74c3c, 600);
}
};
// Always set speedUpgradeBtnText to the SPEED button label when opening the window
speedUpgradeBtnText = btns[0].children[1];
if (speedUpgradeBtnText) {
if (btns[0].coinIcon && btns[0].coinIcon.parent) {
btns[0].coinIcon.parent.removeChild(btns[0].coinIcon);
btns[0].coinIcon = null;
}
if (speedUpgradeLevel < 5) {
speedUpgradeBtnText.setText("SPEED | " + speedUpgradeCost);
var coinAsset = LK.getAsset('coin', {
anchorX: 0.0,
anchorY: 0.5,
scaleX: 0.7,
scaleY: 0.7
});
coinAsset.x = speedUpgradeBtnText.x + speedUpgradeBtnText.width / 2 + coinAsset.width * 0.6;
coinAsset.y = speedUpgradeBtnText.y;
btns[0].addChild(coinAsset);
btns[0].coinIcon = coinAsset;
} else {
speedUpgradeBtnText.setText("SPEED | MAX");
}
}
// --- DAMAGE/POWER UPGRADE LOGIC ---
if (typeof damageUpgradeBtnText === "undefined") damageUpgradeBtnText = null;
damageUpgradeLevel = upgrades.damageUpgradeLevel;
// Override cost to 1 for all levels
damageUpgradeCost = 1;
upgrades.damageUpgradeCost = 1;
btns[1].down = function () {
var upgrades = getWeaponUpgrades(wizardAsset);
// Always set cost to 1 for all levels
upgrades.damageUpgradeCost = 1;
if (coinCount >= upgrades.damageUpgradeCost && upgrades.damageUpgradeLevel < 3) {
coinCount -= upgrades.damageUpgradeCost;
coinText.setText("" + coinCount);
upgrades.damageUpgradeLevel += 1;
upgrades.fireballDamage = 1 + upgrades.damageUpgradeLevel;
// Set next cost: always 1, except maxed
upgrades.damageUpgradeCost = upgrades.damageUpgradeLevel >= 3 ? "-" : 1;
saveWeaponUpgrades(wizardAsset, upgrades);
damageUpgradeLevel = upgrades.damageUpgradeLevel;
damageUpgradeCost = upgrades.damageUpgradeCost;
fireballDamage = upgrades.fireballDamage;
// Update button label to show new cost or disable if maxed
if (damageUpgradeBtnText) {
if (btns[1].coinIcon && btns[1].coinIcon.parent) {
btns[1].coinIcon.parent.removeChild(btns[1].coinIcon);
btns[1].coinIcon = null;
}
if (damageUpgradeLevel < 3) {
damageUpgradeBtnText.setText("DAMAGE | " + damageUpgradeCost);
var coinAsset = LK.getAsset('coin', {
anchorX: 0.0,
anchorY: 0.5,
scaleX: 0.7,
scaleY: 0.7
});
coinAsset.x = damageUpgradeBtnText.x + damageUpgradeBtnText.width / 2 + coinAsset.width * 0.6;
coinAsset.y = damageUpgradeBtnText.y;
btns[1].addChild(coinAsset);
btns[1].coinIcon = coinAsset;
} else {
damageUpgradeBtnText.setText("DAMAGE | MAX");
}
}
LK.effects.flashObject(btns[1], 0x2ecc40, 400);
} else if (damageUpgradeLevel >= 3) {
LK.effects.flashObject(btns[1], 0x888888, 400);
} else {
LK.effects.flashObject(coinText, 0xe74c3c, 600);
}
};
// Always set damageUpgradeBtnText to the POWER button label when opening the window
damageUpgradeBtnText = btns[1].children[1];
if (damageUpgradeBtnText) {
if (btns[1].coinIcon && btns[1].coinIcon.parent) {
btns[1].coinIcon.parent.removeChild(btns[1].coinIcon);
btns[1].coinIcon = null;
}
if (damageUpgradeLevel < 3) {
damageUpgradeBtnText.setText("DAMAGE | " + damageUpgradeCost);
var coinAsset = LK.getAsset('coin', {
anchorX: 0.0,
anchorY: 0.5,
scaleX: 0.7,
scaleY: 0.7
});
coinAsset.x = damageUpgradeBtnText.x + damageUpgradeBtnText.width / 2 + coinAsset.width * 0.6;
coinAsset.y = damageUpgradeBtnText.y;
btns[1].addChild(coinAsset);
btns[1].coinIcon = coinAsset;
} else {
damageUpgradeBtnText.setText("DAMAGE | MAX");
}
}
// HEALTH upgrade logic: cost increases after each purchase, +2 max health, +2 current health, max 3 upgrades: 25, 50, 75 coin
healthUpgradeLevel = upgrades.healthUpgradeLevel;
// Override cost to 1 for all levels
healthUpgradeCost = 1;
upgrades.healthUpgradeCost = 1;
maxWizardHealth = upgrades.maxWizardHealth;
wizardHealth = upgrades.wizardHealth;
btns[2].down = function () {
var upgrades = getWeaponUpgrades(wizardAsset);
// Always set cost to 1 for all levels
upgrades.healthUpgradeCost = 1;
if (coinCount >= upgrades.healthUpgradeCost && upgrades.healthUpgradeLevel < 3) {
coinCount -= upgrades.healthUpgradeCost;
coinText.setText("" + coinCount);
upgrades.maxWizardHealth += 2;
upgrades.wizardHealth += 2;
updateHealthBar();
upgrades.healthUpgradeLevel += 1;
// Set next cost: always 1, except maxed
upgrades.healthUpgradeCost = upgrades.healthUpgradeLevel >= 3 ? "-" : 1;
saveWeaponUpgrades(wizardAsset, upgrades);
healthUpgradeLevel = upgrades.healthUpgradeLevel;
healthUpgradeCost = upgrades.healthUpgradeCost;
maxWizardHealth = upgrades.maxWizardHealth;
wizardHealth = upgrades.wizardHealth;
// Update button label to show new cost or disable if maxed
if (healthUpgradeBtnText) {
if (btns[2].coinIcon && btns[2].coinIcon.parent) {
btns[2].coinIcon.parent.removeChild(btns[2].coinIcon);
btns[2].coinIcon = null;
}
if (healthUpgradeLevel < 3) {
healthUpgradeBtnText.setText("HEALTH | " + healthUpgradeCost);
var coinAsset = LK.getAsset('coin', {
anchorX: 0.0,
anchorY: 0.5,
scaleX: 0.7,
scaleY: 0.7
});
coinAsset.x = healthUpgradeBtnText.x + healthUpgradeBtnText.width / 2 + coinAsset.width * 0.6;
coinAsset.y = healthUpgradeBtnText.y;
btns[2].addChild(coinAsset);
btns[2].coinIcon = coinAsset;
} else {
healthUpgradeBtnText.setText("HEALTH | MAX");
}
}
} else if (healthUpgradeLevel >= 3) {
LK.effects.flashObject(btns[2], 0x888888, 400);
} else {
LK.effects.flashObject(coinText, 0xe74c3c, 600);
}
};
// Always set healthUpgradeBtnText to the HEALTH button label when opening the window
healthUpgradeBtnText = btns[2].children[1];
if (healthUpgradeBtnText) {
if (btns[2].coinIcon && btns[2].coinIcon.parent) {
btns[2].coinIcon.parent.removeChild(btns[2].coinIcon);
btns[2].coinIcon = null;
}
if (healthUpgradeLevel < 3) {
healthUpgradeBtnText.setText("HEALTH | " + healthUpgradeCost);
var coinAsset = LK.getAsset('coin', {
anchorX: 0.0,
anchorY: 0.5,
scaleX: 0.7,
scaleY: 0.7
});
coinAsset.x = healthUpgradeBtnText.x + healthUpgradeBtnText.width / 2 + coinAsset.width * 0.6;
coinAsset.y = healthUpgradeBtnText.y;
btns[2].addChild(coinAsset);
btns[2].coinIcon = coinAsset;
} else {
healthUpgradeBtnText.setText("HEALTH | MAX");
}
}
// --- AMMO UPGRADE LOGIC (max 5 upgrades, +5 max ammo per upgrade, cost 80, 160, 240, 320, 400) ---
if (typeof ammoUpgradeBtnText === "undefined") ammoUpgradeBtnText = null;
if (typeof upgrades.ammoUpgradeLevel === "undefined") upgrades.ammoUpgradeLevel = 0;
if (typeof upgrades.ammoUpgradeCost === "undefined") upgrades.ammoUpgradeCost = 80;
if (typeof upgrades.ammoUpgradeAmount === "undefined") upgrades.ammoUpgradeAmount = 0;
var ammoUpgradeLevel = upgrades.ammoUpgradeLevel;
var ammoUpgradeCost = ammoUpgradeLevel < 5 ? 80 * (ammoUpgradeLevel + 1) : "-";
upgrades.ammoUpgradeCost = ammoUpgradeCost;
btns[3].down = function () {
var upgrades = getWeaponUpgrades(wizardAsset);
if (typeof upgrades.ammoUpgradeLevel === "undefined") upgrades.ammoUpgradeLevel = 0;
if (typeof upgrades.ammoUpgradeCost === "undefined") upgrades.ammoUpgradeCost = 80;
if (typeof upgrades.ammoUpgradeAmount === "undefined") upgrades.ammoUpgradeAmount = 0;
upgrades.ammoUpgradeCost = upgrades.ammoUpgradeLevel < 5 ? 80 * (upgrades.ammoUpgradeLevel + 1) : "-";
if (coinCount >= upgrades.ammoUpgradeCost && upgrades.ammoUpgradeLevel < 5) {
coinCount -= upgrades.ammoUpgradeCost;
coinText.setText("" + coinCount);
upgrades.ammoUpgradeLevel += 1;
upgrades.ammoUpgradeAmount = (upgrades.ammoUpgradeAmount || 0) + 5;
upgrades.ammoUpgradeCost = upgrades.ammoUpgradeLevel < 5 ? 80 * (upgrades.ammoUpgradeLevel + 1) : "-";
saveWeaponUpgrades(wizardAsset, upgrades);
ammoUpgradeLevel = upgrades.ammoUpgradeLevel;
ammoUpgradeCost = upgrades.ammoUpgradeCost;
// Increase wizardMaxAmmo for current weapon
if (typeof wizardMaxAmmo !== "undefined") {
wizardMaxAmmo += 5;
wizardAmmo = wizardMaxAmmo;
}
// Update button label
if (ammoUpgradeBtnText) {
if (btns[3].coinIcon && btns[3].coinIcon.parent) {
btns[3].coinIcon.parent.removeChild(btns[3].coinIcon);
btns[3].coinIcon = null;
}
if (ammoUpgradeLevel < 5) {
ammoUpgradeBtnText.setText("AMMO | " + ammoUpgradeCost);
var coinAsset = LK.getAsset('coin', {
anchorX: 0.0,
anchorY: 0.5,
scaleX: 0.7,
scaleY: 0.7
});
coinAsset.x = ammoUpgradeBtnText.x + ammoUpgradeBtnText.width / 2 + coinAsset.width * 0.6;
coinAsset.y = ammoUpgradeBtnText.y;
btns[3].addChild(coinAsset);
btns[3].coinIcon = coinAsset;
} else {
ammoUpgradeBtnText.setText("AMMO | MAX");
}
}
LK.effects.flashObject(btns[3], 0x2ecc40, 400);
} else if (ammoUpgradeLevel >= 5) {
LK.effects.flashObject(btns[3], 0x888888, 400);
} else {
LK.effects.flashObject(coinText, 0xe74c3c, 600);
}
};
// Always set ammoUpgradeBtnText to the AMMO button label when opening the window
ammoUpgradeBtnText = btns[3].children[1];
if (ammoUpgradeBtnText) {
if (btns[3].coinIcon && btns[3].coinIcon.parent) {
btns[3].coinIcon.parent.removeChild(btns[3].coinIcon);
btns[3].coinIcon = null;
}
if (ammoUpgradeLevel < 5) {
ammoUpgradeBtnText.setText("AMMO | " + ammoUpgradeCost);
var coinAsset = LK.getAsset('coin', {
anchorX: 0.0,
anchorY: 0.5,
scaleX: 0.7,
scaleY: 0.7
});
coinAsset.x = ammoUpgradeBtnText.x + ammoUpgradeBtnText.width / 2 + coinAsset.width * 0.6;
coinAsset.y = ammoUpgradeBtnText.y;
btns[3].addChild(coinAsset);
btns[3].coinIcon = coinAsset;
} else {
ammoUpgradeBtnText.setText("AMMO | MAX");
}
}
// BACK button without coin asset
// Place it 500 units further from AMMO (btnSpacing = 220, so AMMO is at -180 + 3*220 = 480, BACK at 480+400=880)
var geriBtn = makeUpgradeBtn("BACK", 880, undefined, null, undefined);
upgradeWindow.addChild(geriBtn);
// BACK closes window
geriBtn.down = function () {
if (upgradeWindow && !upgradeWindow.destroyed) {
upgradeWindow.destroy();
upgradeWindow = null;
}
};
// Center window
upgradeWindow.x = 2048 / 2;
upgradeWindow.y = 2732 / 2;
game.addChild(upgradeWindow);
}
// Upgrade button interaction
upgradeButton.down = function (x, y, obj) {
if (upgradeWindow && !upgradeWindow.destroyed) return;
showUpgradeWindow();
};
// --- SHOP WINDOW LOGIC ---
var shopWindow = null;
function showShopWindow() {
if (shopWindow && !shopWindow.destroyed) return;
shopWindow = new Container();
// Window background
var winW = 1500;
var winH = 2000;
var winBg = LK.getAsset('shop', {
anchorX: 0.5,
anchorY: 0.5,
width: winW,
height: winH
});
winBg.alpha = 0.97;
shopWindow.addChild(winBg);
// Title text removed
// Weapon shop items
var weaponList = [{
name: "SMG",
asset: "submachine",
price: 1
}, {
name: "SAG",
asset: "MP5",
price: 150
}, {
name: "Shuriken",
asset: "shuriken",
price: 150
}, {
name: "Shotgun",
asset: "shotgun",
price: 250
}, {
name: "Minigun",
asset: "minigun",
price: 350
}, {
name: "Laser Gun",
asset: "Lasergun",
price: 750
}];
var itemStartY = -350;
var itemSpacing = 220;
var shopItemButtons = [];
var _loop = function _loop() {
weapon = weaponList[i];
itemY = itemStartY + i * itemSpacing;
shopItem = new Container(); // Icon (left)
itemIcon = LK.getAsset(weapon.asset, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.0,
scaleY: 1.0,
x: -420,
y: 0
});
shopItem.addChild(itemIcon);
// "SMG | x" text (centered)
itemText = new Text2(weapon.name + " | " + weapon.price, {
size: 90,
fill: "#fff"
});
itemText.anchor.set(0, 0.5);
itemText.x = -180;
itemText.y = 0;
shopItem.addChild(itemText);
// Coin asset (right of price)
priceCoin = LK.getAsset('coin', {
anchorX: 0.0,
anchorY: 0.5,
scaleX: 0.7,
scaleY: 0.7,
x: itemText.x + itemText.width + 30,
y: itemText.y
});
shopItem.addChild(priceCoin);
// PURCHASED label (hidden by default)
purchasedLabel = new Text2("PURCHASED", {
size: 80,
fill: 0x2ECC40
});
purchasedLabel.anchor.set(0, 0.5);
purchasedLabel.x = itemText.x + itemText.width + 120;
purchasedLabel.y = itemText.y;
purchasedLabel.visible = false;
shopItem.addChild(purchasedLabel);
// SELECTED label (hidden by default)
selectedLabel = new Text2("SELECTED", {
size: 80,
fill: 0xFFD700
});
selectedLabel.anchor.set(0, 0.5);
selectedLabel.x = itemText.x + itemText.width + 120;
selectedLabel.y = itemText.y;
selectedLabel.visible = false;
shopItem.addChild(selectedLabel);
// Helper to update purchased/selected state visuals
function updateShopItemState() {
var isPurchased = shopPurchases && shopPurchases[weapon.asset];
var isSelected = wizardAsset === weapon.asset;
purchasedLabel.visible = !!isPurchased && !isSelected;
selectedLabel.visible = !!isPurchased && isSelected;
if (!!isPurchased && isSelected) {
priceCoin.visible = false;
itemText.setText(weapon.name);
} else {
priceCoin.visible = !isPurchased;
itemText.setText(weapon.name + (isPurchased ? "" : " | " + weapon.price));
}
// --- Fix: Ensure only one SELECTED label is visible at a time ---
if (!!isPurchased && isSelected) {
// Hide SELECTED on all other shop items
for (var si = 0; si < shopItemButtons.length; si++) {
if (shopItemButtons[si] !== shopItem && shopItemButtons[si].children) {
for (var ci = 0; ci < shopItemButtons[si].children.length; ci++) {
var child = shopItemButtons[si].children[ci];
if (child && child.text === "SELECTED") {
child.visible = false;
}
}
}
}
}
}
updateShopItemState();
// Add down handler for all shop items
(function (weapon, shopItem, purchasedLabel, selectedLabel, priceCoin, itemText, updateShopItemState) {
shopItem.down = function () {
var isPurchased = shopPurchases && shopPurchases[weapon.asset];
var isSelected = wizardAsset === weapon.asset;
if (isPurchased) {
// If already purchased, always update SELECTED label immediately
if (!isSelected) {
// Remove all children to ensure only one wizard asset
for (var i = wizard.children.length - 1; i >= 0; i--) {
wizard.removeChild(wizard.children[i]);
}
// Add new asset as wizard's appearance
var newSprite = wizard.attachAsset(weapon.asset, {
anchorX: 0.5,
anchorY: 0.5
});
// Save wizard asset
storage.wizardAsset = weapon.asset;
wizardAsset = weapon.asset;
// Switch upgrades to selected weapon
currentWeaponUpgrades = getWeaponUpgrades(wizardAsset);
speedUpgradeLevel = currentWeaponUpgrades.speedUpgradeLevel;
speedUpgradeCost = currentWeaponUpgrades.speedUpgradeCost;
damageUpgradeLevel = currentWeaponUpgrades.damageUpgradeLevel;
damageUpgradeCost = currentWeaponUpgrades.damageUpgradeCost;
healthUpgradeLevel = currentWeaponUpgrades.healthUpgradeLevel;
healthUpgradeCost = currentWeaponUpgrades.healthUpgradeCost;
maxWizardHealth = currentWeaponUpgrades.maxWizardHealth;
wizardHealth = currentWeaponUpgrades.wizardHealth;
fireballDamage = currentWeaponUpgrades.fireballDamage;
// --- Minigun ayarları ---
if (weapon.asset === "minigun") {
// Minigun için mermi asseti ve şarjör ayarları
wizardMaxAmmo = applyAmmoUpgradeToMaxAmmo("minigun");
wizardAmmo = wizardMaxAmmo;
wizardReloadTime = 2000;
tapFireCooldown = 500;
// Minigun için fireball yerine minigunbullet kullanılacak, shootFireballAt fonksiyonunda kontrol edilecek
wizardBulletType = "minigunbullet";
} else if (weapon.asset === "shuriken") {
wizardBulletType = "shurikenbullet";
wizardMaxAmmo = applyAmmoUpgradeToMaxAmmo("shuriken");
wizardAmmo = wizardMaxAmmo;
wizardReloadTime = 2000;
tapFireCooldown = 750;
} else if (weapon.asset === "shotgun") {
wizardBulletType = null;
wizardMaxAmmo = applyAmmoUpgradeToMaxAmmo("shotgun");
wizardAmmo = wizardMaxAmmo;
wizardReloadTime = 1000;
tapFireCooldown = 200;
} else if (weapon.asset === "submachine") {
wizardBulletType = null;
wizardMaxAmmo = applyAmmoUpgradeToMaxAmmo("submachine");
wizardAmmo = wizardMaxAmmo;
wizardReloadTime = 500;
tapFireCooldown = 100;
} else if (weapon.asset === "Lasergun") {
wizardBulletType = "lasergunbullet";
wizardMaxAmmo = applyAmmoUpgradeToMaxAmmo("Lasergun");
wizardAmmo = wizardMaxAmmo;
wizardReloadTime = 1200;
tapFireCooldown = 300;
} else {
// Diğer silahlar için default ayarlar
wizardBulletType = null;
wizardMaxAmmo = applyAmmoUpgradeToMaxAmmo(wizardAsset);
wizardAmmo = wizardMaxAmmo;
wizardReloadTime = 2000;
tapFireCooldown = Math.max(100, 850 - speedUpgradeLevel * 150);
}
// Move health bar above new asset
// Health bar is now fixed in the GUI, no need to reposition here
// Feedback
LK.effects.flashObject(wizard, 0x2ecc40, 400);
}
// Update visuals for all shop items, so SELECTED label is always correct
for (var si = 0; si < shopItemButtons.length; si++) {
if (shopItemButtons[si].updateShopItemState) shopItemButtons[si].updateShopItemState();
}
// If already selected, do nothing else
return;
}
// Not purchased yet
if (coinCount >= weapon.price) {
coinCount -= weapon.price;
coinText.setText("" + coinCount);
// Remove all children to ensure only one wizard asset
for (var i = wizard.children.length - 1; i >= 0; i--) {
wizard.removeChild(wizard.children[i]);
}
// Add new asset as wizard's appearance
var newSprite = wizard.attachAsset(weapon.asset, {
anchorX: 0.5,
anchorY: 0.5
});
// Save wizard asset and shop purchase
storage.wizardAsset = weapon.asset;
wizardAsset = weapon.asset;
// Switch upgrades to selected weapon
currentWeaponUpgrades = getWeaponUpgrades(wizardAsset);
speedUpgradeLevel = currentWeaponUpgrades.speedUpgradeLevel;
speedUpgradeCost = currentWeaponUpgrades.speedUpgradeCost;
damageUpgradeLevel = currentWeaponUpgrades.damageUpgradeLevel;
damageUpgradeCost = currentWeaponUpgrades.damageUpgradeCost;
healthUpgradeLevel = currentWeaponUpgrades.healthUpgradeLevel;
healthUpgradeCost = currentWeaponUpgrades.healthUpgradeCost;
maxWizardHealth = currentWeaponUpgrades.maxWizardHealth;
wizardHealth = currentWeaponUpgrades.wizardHealth;
fireballDamage = currentWeaponUpgrades.fireballDamage;
if (!shopPurchases) shopPurchases = {};
shopPurchases[weapon.asset] = true;
storage.shopPurchases = shopPurchases;
// --- Minigun ayarları ---
if (weapon.asset === "minigun") {
// Minigun için mermi asseti ve şarjör ayarları
wizardMaxAmmo = 150;
wizardAmmo = wizardMaxAmmo;
wizardReloadTime = 2000;
tapFireCooldown = 500;
wizardBulletType = "minigunbullet";
} else if (weapon.asset === "shuriken") {
// Shuriken için sonsuz mermi
wizardBulletType = "shurikenbullet";
wizardMaxAmmo = 7;
wizardAmmo = wizardMaxAmmo;
wizardReloadTime = 2000;
tapFireCooldown = 750;
} else if (weapon.asset === "shotgun") {
wizardBulletType = null;
wizardMaxAmmo = 2;
wizardAmmo = wizardMaxAmmo;
wizardReloadTime = 1000;
tapFireCooldown = 200;
} else if (weapon.asset === "submachine") {
wizardBulletType = null;
wizardMaxAmmo = 3;
wizardAmmo = wizardMaxAmmo;
wizardReloadTime = 500;
tapFireCooldown = 100;
} else if (weapon.asset === "Lasergun") {
wizardBulletType = "lasergunbullet";
wizardMaxAmmo = 10;
wizardAmmo = wizardMaxAmmo;
wizardReloadTime = 1200;
tapFireCooldown = 300;
} else {
// Diğer silahlar için default ayarlar
wizardBulletType = null;
wizardMaxAmmo = 7;
wizardAmmo = wizardMaxAmmo;
wizardReloadTime = 2000;
tapFireCooldown = Math.max(100, 850 - speedUpgradeLevel * 150);
}
// Move health bar above new asset
// Health bar is now fixed in the GUI, no need to reposition here
// Feedback
LK.effects.flashObject(wizard, 0x2ecc40, 400);
// Update visuals for all shop items
for (var si = 0; si < shopItemButtons.length; si++) {
if (shopItemButtons[si].updateShopItemState) shopItemButtons[si].updateShopItemState();
}
} else {
LK.effects.flashObject(coinText, 0xe74c3c, 600);
}
};
// Attach state update helper for global update
shopItem.updateShopItemState = updateShopItemState;
})(weapon, shopItem, purchasedLabel, selectedLabel, priceCoin, itemText, updateShopItemState);
shopItem.x = 0;
shopItem.y = itemY;
shopWindow.addChild(shopItem);
shopItemButtons.push(shopItem);
},
weapon,
itemY,
shopItem,
itemIcon,
itemText,
priceCoin,
purchasedLabel,
selectedLabel;
for (var i = 0; i < weaponList.length; i++) {
_loop();
}
// BACK button
var backBtn = new Container();
// No background for back button
var backBtnText = new Text2("BACK", {
size: 90,
fill: "#fff"
});
backBtnText.anchor.set(0.5, 0.5);
backBtnText.x = 0;
backBtnText.y = 0;
backBtn.addChild(backBtnText);
backBtn.x = 0;
backBtn.y = itemStartY + weaponList.length * itemSpacing + 80;
shopWindow.addChild(backBtn);
backBtn.down = function () {
if (shopWindow && !shopWindow.destroyed) {
shopWindow.destroy();
shopWindow = null;
}
};
// Center window
shopWindow.x = 2048 / 2;
shopWindow.y = 2732 / 2;
game.addChild(shopWindow);
}
// Shop button interaction
shopButton.down = function (x, y, obj) {
if (shopWindow && !shopWindow.destroyed) return;
showShopWindow();
};
// Start button interaction
startButton.down = function (x, y, obj) {
if (gameStarted) return;
gameStarted = true;
// Remove start UI container (removes both start and upgrade buttons)
if (startUiContainer && !startUiContainer.destroyed) {
startUiContainer.destroy();
}
// --- RESET GAME STATE ---
// Remove all enemies, fireballs, coins from game and arrays
for (var i = enemies.length - 1; i >= 0; i--) {
if (enemies[i] && !enemies[i].destroyed) enemies[i].destroy();
enemies.splice(i, 1);
}
for (var i = fireballs.length - 1; i >= 0; i--) {
if (fireballs[i] && !fireballs[i].destroyed) fireballs[i].destroy();
fireballs.splice(i, 1);
}
for (var i = coins.length - 1; i >= 0; i--) {
if (coins[i] && !coins[i].destroyed) coins[i].destroy();
coins.splice(i, 1);
}
// Reset score and coin count
score = 0;
// coinCount is NOT reset here, so coins are preserved when starting a new game
scoreText.setText("Score: 0");
coinText.setText("" + coinCount);
// Center wizard
wizard.x = 2048 / 2;
wizard.y = 2732 / 2;
// Remove all children to ensure only one wizard asset
for (var i = wizard.children.length - 1; i >= 0; i--) {
wizard.removeChild(wizard.children[i]);
}
// Attach wizard asset if not present
var hasWizardSprite = false;
for (var i = 0; i < wizard.children.length; i++) {
hasWizardSprite = true;
break;
}
if (!hasWizardSprite) {
var newSprite = wizard.attachAsset(wizardAsset, {
anchorX: 0.5,
anchorY: 0.5
});
if (newSprite) {
newSprite.rotation = Math.PI;
}
} else if (wizard.children && wizard.children.length > 0) {
wizard.children[0].rotation = Math.PI; // face left
}
// Reset health
wizardHealth = maxWizardHealth;
updateHealthBar();
// Enable game input
game.move = originalGameMove;
game.down = originalGameDown;
game.up = originalGameUp;
};
// Save original handlers for restoration
var originalGameMove = function originalGameMove(x, y, obj) {
// Wizard is fixed; do nothing
// Calculate angle from wizard to pointer/touch and rotate wizard sprite
var dx = x - wizard.x;
var dy = y - wizard.y;
var angle = Math.atan2(dy, dx);
// Wizard's default asset faces left, so add Math.PI to rotate to correct direction
if (wizard.children && wizard.children.length > 0) {
wizard.children[0].rotation = angle + Math.PI;
}
// If firing, update direction for continuous fire
if (isFiring) {
lastFireX = x;
lastFireY = y;
}
};
var originalGameDown = function originalGameDown(x, y, obj) {
var now = Date.now();
if (now - lastTapFireTime < tapFireCooldown) {
// Too soon, ignore this tap for firing
return;
}
lastTapFireTime = now;
isFiring = true;
lastFireX = x;
lastFireY = y;
shootFireballAt(x, y);
if (fireInterval) LK.clearInterval(fireInterval);
fireInterval = LK.setInterval(function () {
if (isFiring) {
shootFireballAt(lastFireX, lastFireY);
}
}, tapFireCooldown); // fire every tapFireCooldown ms when holding down
};
var originalGameUp = function originalGameUp(x, y, obj) {
isFiring = false;
if (fireInterval) {
LK.clearInterval(fireInterval);
fireInterval = null;
}
};
// Array to hold all fireballs
var fireballs = [];
// Array to hold all boss bullets
var bossBullets = [];
// Helper: get direction vector from wizard to (x, y)
function getDirection(fromX, fromY, toX, toY, speed) {
var dx = toX - fromX;
var dy = toY - fromY;
var len = Math.sqrt(dx * dx + dy * dy);
if (len === 0) return {
vx: 0,
vy: 0
};
return {
vx: dx / len * speed,
vy: dy / len * speed
};
}
// Dragging wizard with mouse/touch (disabled)
var dragging = false;
// Move handler: wizard does not move
game.move = function (x, y, obj) {
if (!gameStarted) return; // Only rotate wizard during gameplay
// Calculate angle from wizard to pointer/touch and rotate wizard sprite
var dx = x - wizard.x;
var dy = y - wizard.y;
var angle = Math.atan2(dy, dx);
// Wizard's default asset faces left, so add Math.PI to rotate to correct direction
if (wizard.children && wizard.children.length > 0) {
wizard.children[0].rotation = angle + Math.PI;
}
// If firing, update direction for continuous fire
if (isFiring) {
lastFireX = x;
lastFireY = y;
}
};
// Track if fire is being held
var isFiring = false;
var fireInterval = null;
var lastFireX = 0;
// --- Magazine system for wizard weapon ---
var wizardMaxAmmo = 7;
var wizardAmmo = wizardMaxAmmo;
var wizardReloading = false;
var wizardReloadTime = 2000; // ms
var wizardReloadTimeout = null;
// Hangi mermi asseti kullanılacak? (null: default, "shurikenbullet", "minigunbullet")
var wizardBulletType = null;
// Helper: apply ammo upgrade to wizardMaxAmmo for current weapon
function applyAmmoUpgradeToMaxAmmo(weaponAsset) {
var upgrades = getWeaponUpgrades(weaponAsset);
var baseMaxAmmo = 7;
if (weaponAsset === "minigun") baseMaxAmmo = 150;else if (weaponAsset === "shuriken") baseMaxAmmo = 7;else if (weaponAsset === "shotgun") baseMaxAmmo = 2;else if (weaponAsset === "submachine") baseMaxAmmo = 3;else if (weaponAsset === "Lasergun") baseMaxAmmo = 10;
// Add ammoUpgradeAmount if present
if (typeof upgrades.ammoUpgradeAmount === "number") {
return baseMaxAmmo + upgrades.ammoUpgradeAmount;
}
return baseMaxAmmo;
}
// Cooldown for tap-to-fire (now 850ms)
var lastTapFireTime = 0;
var tapFireCooldown = 850;
function shootFireballAt(x, y) {
// --- Magazine system: block fire if out of ammo or reloading ---
// For shuriken, skip ammo/reload logic (infinite ammo)
if (wizardAsset !== "shuriken") {
if (wizardReloading) {
// Can't shoot while reloading
return;
}
if (wizardAmmo <= 0) {
// Start reload if not already reloading
if (!wizardReloading) {
wizardReloading = true;
wizardReloadTimeout = LK.setTimeout(function () {
wizardAmmo = wizardMaxAmmo;
wizardReloading = false;
wizardReloadTimeout = null;
}, wizardReloadTime);
}
return;
}
// Decrease ammo
wizardAmmo--;
}
// Eğer wizardAsset shuriken ise shurikenbullet fırlat
if (wizardAsset === "shuriken") {
// SPEED upgrade seviyesine göre shuriken için özel ateş aralığı ve mermi hızı uygulanacak
var upgrades = getWeaponUpgrades(wizardAsset);
var speedLevel = upgrades.speedUpgradeLevel || 0;
// Shuriken için yeni seviye tablosu:
// | Seviye | Ateş Aralığı (ms) | Mermi Hızı (birim/frame) |
// | 0 | 850 | 18 |
// | 1 | 762 | 19.5 |
// | 2 | 675 | 21 |
// | 3 | 587 | 22.5 |
// | 4 | 500 | 24 |
var shurikenFireIntervals = [850, 762, 675, 587, 500];
var shurikenBulletSpeeds = [18, 19.5, 21, 22.5, 24];
var fireInterval = shurikenFireIntervals[Math.min(speedLevel, 4)];
var bulletSpeed = shurikenBulletSpeeds[Math.min(speedLevel, 4)];
tapFireCooldown = fireInterval;
// Fire 3 shurikenbullets at -15, 0, +15 degrees from the main direction
var baseDir = getDirection(wizard.x, wizard.y, x, y, bulletSpeed);
var baseAngle = Math.atan2(baseDir.vy, baseDir.vx);
var angles = [-15, 0, 15];
for (var i = 0; i < angles.length; i++) {
var angleRad = baseAngle + angles[i] * Math.PI / 180;
var vx = Math.cos(angleRad) * bulletSpeed;
var vy = Math.sin(angleRad) * bulletSpeed;
var fireball = new Fireball();
// Remove default fireball sprite, add shurikenbullet
if (fireball.children && fireball.children.length > 0) {
var oldSprite = fireball.children[0];
fireball.removeChild(oldSprite);
}
var shurikenBulletSprite = fireball.attachAsset('shurikenbullet', {
anchorX: 0.5,
anchorY: 0.5
});
fireball.x = wizard.x;
fireball.y = wizard.y;
fireball.vx = vx;
fireball.vy = vy;
if (fireball.children && fireball.children.length > 0) {
fireball.children[0].rotation = angleRad;
}
if (wizard.children && wizard.children.length > 0 && angles[i] === 0) {
wizard.children[0].rotation = baseAngle + Math.PI;
}
fireballs.push(fireball);
game.addChild(fireball);
}
LK.getSound('shuriken').play();
} else {
// SMG logic
if (wizardAsset === "submachine") {
tapFireCooldown = 100;
wizardReloadTime = 500;
var baseDir = getDirection(wizard.x, wizard.y, x, y, 8);
var baseAngle = Math.atan2(baseDir.vy, baseDir.vx);
// Fire only 1 bullet per shot (no in-a-row)
var fireball = new Fireball();
fireball.x = wizard.x;
fireball.y = wizard.y;
fireball.vx = Math.cos(baseAngle) * 8;
fireball.vy = Math.sin(baseAngle) * 8;
if (fireball.children && fireball.children.length > 0) {
fireball.children[0].rotation = baseAngle;
}
fireballs.push(fireball);
game.addChild(fireball);
if (wizard.children && wizard.children.length > 0) {
wizard.children[0].rotation = baseAngle + Math.PI;
}
// Play SMG sound (use fire sound as placeholder if SMG sound not available)
if (LK.getSound('SMG')) {
LK.getSound('SMG').play();
} else {
LK.getSound('fire').play();
}
// Start reload if out of ammo after this shot
if (wizardAmmo <= 0 && !wizardReloading) {
wizardReloading = true;
wizardReloadTimeout = LK.setTimeout(function () {
wizardAmmo = wizardMaxAmmo;
wizardReloading = false;
wizardReloadTimeout = null;
}, wizardReloadTime);
}
} else
// Shotgun logic
if (wizardAsset === "shotgun") {
// --- SPEED UPGRADE: Shotgun için özel ateş ve mermi hızları (800ms -> 500ms) ---
var upgrades = getWeaponUpgrades("shotgun");
var speedLevel = upgrades.speedUpgradeLevel || 0;
// Yeni seviye tablosu:
// | Seviye | Ateş Aralığı (ms) | Mermi Hızı (birim/frame) |
// | 0 | 800 | 10 |
// | 1 | 725 | 11 |
// | 2 | 650 | 12 |
// | 3 | 575 | 13 |
// | 4 | 500 | 14 |
var shotgunFireIntervals = [800, 725, 650, 575, 500];
var shotgunBulletSpeeds = [10, 11, 12, 13, 14];
var fireInterval = shotgunFireIntervals[Math.min(speedLevel, 4)];
var bulletSpeed = shotgunBulletSpeeds[Math.min(speedLevel, 4)];
tapFireCooldown = fireInterval;
wizardReloadTime = 1000;
// 5 bullets, 75-degree random spread
var baseDir = getDirection(wizard.x, wizard.y, x, y, bulletSpeed);
var baseAngle = Math.atan2(baseDir.vy, baseDir.vx);
for (var i = 0; i < 5; i++) {
var spreadDeg = Math.random() * 75 - 37.5;
var angleRad = baseAngle + spreadDeg * Math.PI / 180;
var vx = Math.cos(angleRad) * bulletSpeed;
var vy = Math.sin(angleRad) * bulletSpeed;
var fireball = new Fireball();
fireball.x = wizard.x;
fireball.y = wizard.y;
fireball.vx = vx;
fireball.vy = vy;
if (fireball.children && fireball.children.length > 0) {
fireball.children[0].rotation = angleRad;
}
fireballs.push(fireball);
game.addChild(fireball);
}
if (wizard.children && wizard.children.length > 0) {
wizard.children[0].rotation = baseAngle + Math.PI;
}
// Play shotgun sound (use fire sound as placeholder if shotgun sound not available)
if (LK.getSound('shotgun')) {
LK.getSound('shotgun').play();
} else {
LK.getSound('fire').play();
}
// Start reload if out of ammo after this shot
if (wizardAmmo <= 0 && !wizardReloading) {
wizardReloading = true;
wizardReloadTimeout = LK.setTimeout(function () {
wizardAmmo = wizardMaxAmmo;
wizardReloading = false;
wizardReloadTimeout = null;
}, wizardReloadTime);
}
} else
// Minigun için özel asset ve ayarlar
if (wizardAsset === "minigun" || wizardBulletType === "minigunbullet") {
// --- SPEED UPGRADE: Minigun için özel ateş ve mermi hızları ---
var upgrades = getWeaponUpgrades("minigun");
var speedLevel = upgrades.speedUpgradeLevel || 0;
// Seviye tablosu:
// | Seviye | Ateş Aralığı (ms) | Mermi Hızı (birim/frame) |
// | 0 | 500 | 18 |
// | 1 | 360 | 19.5 |
// | 2 | 220 | 21 |
// | 3 | 150 | 22.5 |
// | 4 | 80 | 24 |
var minigunFireIntervals = [500, 360, 220, 150, 80];
var minigunBulletSpeeds = [18, 19.5, 21, 22.5, 24];
var fireInterval = minigunFireIntervals[Math.min(speedLevel, 4)];
var bulletSpeed = minigunBulletSpeeds[Math.min(speedLevel, 4)];
tapFireCooldown = fireInterval;
// Fire 1 bullet per tap, but with random scatter in a 30-degree cone
var baseDir = getDirection(wizard.x, wizard.y, x, y, bulletSpeed);
var baseAngle = Math.atan2(baseDir.vy, baseDir.vx);
// 30-degree cone: -15 to +15 deg, random within
var scatterDeg = Math.random() * 30 - 15;
var scatterRad = scatterDeg * Math.PI / 180;
var angle = baseAngle + scatterRad;
var vx = Math.cos(angle) * bulletSpeed;
var vy = Math.sin(angle) * bulletSpeed;
var fireball = new Fireball();
fireball.x = wizard.x;
fireball.y = wizard.y;
fireball.vx = vx;
fireball.vy = vy;
// Default fireball asseti kaldır, minigunbullet ekle
if (fireball.children && fireball.children.length > 0) {
var oldSprite = fireball.children[0];
fireball.removeChild(oldSprite);
}
var minigunBulletSprite = fireball.attachAsset('minigunbullet', {
anchorX: 0.5,
anchorY: 0.5
});
if (fireball.children && fireball.children.length > 0) {
fireball.children[0].rotation = angle;
}
if (wizard.children && wizard.children.length > 0) {
wizard.children[0].rotation = Math.atan2(y - wizard.y, x - wizard.x) + Math.PI;
}
fireballs.push(fireball);
game.addChild(fireball);
LK.getSound('Minigun').play();
// Start reload if out of ammo after this shot
if (wizardAmmo <= 0 && !wizardReloading) {
wizardReloading = true;
wizardReloadTimeout = LK.setTimeout(function () {
wizardAmmo = wizardMaxAmmo;
wizardReloading = false;
wizardReloadTimeout = null;
}, wizardReloadTime);
}
} else if (wizardAsset === "Lasergun" || wizardBulletType === "lasergunbullet") {
// --- SPEED UPGRADE: Lasergun için yeni ateş ve mermi hızları (750ms -> 200ms) ---
var upgrades = getWeaponUpgrades("Lasergun");
var speedLevel = upgrades.speedUpgradeLevel || 0;
// Seviye tablosu:
// | Seviye | Ateş Aralığı (ms) | Mermi Hızı (birim/frame) |
// | 0 | 750 | 18 |
// | 1 | 550 | 19.5 |
// | 2 | 400 | 21 |
// | 3 | 300 | 22.5 |
// | 4 | 200 | 24 |
var lasergunFireIntervals = [750, 550, 400, 300, 200];
var lasergunBulletSpeeds = [18, 19.5, 21, 22.5, 24];
var fireInterval = lasergunFireIntervals[Math.min(speedLevel, 4)];
var bulletSpeed = lasergunBulletSpeeds[Math.min(speedLevel, 4)];
tapFireCooldown = fireInterval;
var baseDir = getDirection(wizard.x, wizard.y, x, y, bulletSpeed);
var baseAngle = Math.atan2(baseDir.vy, baseDir.vx);
// Fire 3 lasergun bullets in a row, no spread
for (var i = 0; i < 3; i++) {
var fireball = new Fireball();
fireball.x = wizard.x;
fireball.y = wizard.y;
fireball.vx = Math.cos(baseAngle) * bulletSpeed;
fireball.vy = Math.sin(baseAngle) * bulletSpeed;
// Remove default fireball sprite, add lasergunbullet
if (fireball.children && fireball.children.length > 0) {
var oldSprite = fireball.children[0];
fireball.removeChild(oldSprite);
}
var laserBulletSprite = fireball.attachAsset('lasergunbullet', {
anchorX: 0.5,
anchorY: 0.5
});
if (fireball.children && fireball.children.length > 0) {
fireball.children[0].rotation = baseAngle;
}
// Only rotate wizard sprite for the center bullet
if (wizard.children && wizard.children.length > 0 && i === 1) {
wizard.children[0].rotation = Math.atan2(y - wizard.y, x - wizard.x) + Math.PI;
}
fireballs.push(fireball);
game.addChild(fireball);
}
LK.getSound('plasma').play();
// Start reload if out of ammo after this shot
if (wizardAmmo <= 0 && !wizardReloading) {
wizardReloading = true;
wizardReloadTimeout = LK.setTimeout(function () {
wizardAmmo = wizardMaxAmmo;
wizardReloading = false;
wizardReloadTimeout = null;
}, wizardReloadTime);
}
} else {
// Restore tapFireCooldown to upgrade-based value for non-shuriken weapons
// SPEED upgrade seviyesine göre mermi hızı artırımı
var upgrades = getWeaponUpgrades(wizardAsset);
var speedLevel = upgrades.speedUpgradeLevel || 0;
var bulletSpeed = 8 + speedLevel * 1.5; // her seviye +1.5 hız
tapFireCooldown = Math.max(80, 850 - speedLevel * 140);
var fireball = new Fireball();
fireball.x = wizard.x;
fireball.y = wizard.y;
var dir = getDirection(wizard.x, wizard.y, x, y, bulletSpeed);
fireball.vx = dir.vx;
fireball.vy = dir.vy;
var angle = Math.atan2(dir.vy, dir.vx);
if (fireball.children && fireball.children.length > 0) {
fireball.children[0].rotation = angle;
}
if (wizard.children && wizard.children.length > 0) {
wizard.children[0].rotation = Math.atan2(y - wizard.y, x - wizard.x) + Math.PI;
}
fireballs.push(fireball);
game.addChild(fireball);
LK.getSound('fire').play();
// Start reload if out of ammo after this shot
if (wizardAmmo <= 0 && !wizardReloading) {
wizardReloading = true;
wizardReloadTimeout = LK.setTimeout(function () {
wizardAmmo = wizardMaxAmmo;
wizardReloading = false;
wizardReloadTimeout = null;
}, wizardReloadTime);
}
}
}
}
// Down handler: start firing repeatedly only if gameStarted
game.down = function (x, y, obj) {
if (!gameStarted) return;
var now = Date.now();
if (now - lastTapFireTime < tapFireCooldown) {
// Too soon, ignore this tap for firing
return;
}
lastTapFireTime = now;
isFiring = true;
lastFireX = x;
lastFireY = y;
shootFireballAt(x, y);
if (fireInterval) LK.clearInterval(fireInterval);
fireInterval = LK.setInterval(function () {
if (isFiring) {
shootFireballAt(lastFireX, lastFireY);
}
}, tapFireCooldown); // fire every tapFireCooldown ms when holding down
};
// Up handler: stop firing only if gameStarted
game.up = function (x, y, obj) {
if (!gameStarted) return;
isFiring = false;
if (fireInterval) {
LK.clearInterval(fireInterval);
fireInterval = null;
}
};
// Array to hold all enemies
var enemies = [];
// Import storage plugin for persistent coin saving
// Array to hold all coins
var coins = [];
// Wizard health system
var wizardHealth = 5;
var maxWizardHealth = 5;
// Health upgrade cost system
var healthUpgradeCost = 25;
var healthUpgradeBtnText = null;
var healthUpgradeLevel = 0;
// --- Per-weapon upgrade system ---
var weaponUpgradeDefaults = {
speedUpgradeLevel: 0,
speedUpgradeCost: 100,
// ilk seviye 100 coin
damageUpgradeLevel: 0,
damageUpgradeCost: 60,
healthUpgradeLevel: 0,
healthUpgradeCost: 25,
maxWizardHealth: 5,
wizardHealth: 5,
fireballDamage: 1,
// --- Ammo upgrade fields ---
ammoUpgradeLevel: 0,
ammoUpgradeCost: 80,
ammoUpgradeAmount: 0
};
// Helper to get upgrade key for a weapon
function getWeaponUpgradeKey(weaponAsset) {
return "weaponUpgrades_" + weaponAsset;
}
// Helper to get upgrades for a weapon (returns object)
function getWeaponUpgrades(weaponAsset) {
var key = getWeaponUpgradeKey(weaponAsset);
var upgrades = storage[key];
if (!upgrades) {
upgrades = {};
// Copy defaults
for (var k in weaponUpgradeDefaults) upgrades[k] = weaponUpgradeDefaults[k];
storage[key] = upgrades;
} else {
// Fill in any missing defaults
for (var k in weaponUpgradeDefaults) {
if (typeof upgrades[k] === "undefined") upgrades[k] = weaponUpgradeDefaults[k];
}
}
return upgrades;
}
// Helper to save upgrades for a weapon
function saveWeaponUpgrades(weaponAsset, upgrades) {
var key = getWeaponUpgradeKey(weaponAsset);
storage[key] = upgrades;
}
// --- Current weapon upgrades (populated on load and on weapon change) ---
var currentWeaponUpgrades = getWeaponUpgrades(wizardAsset);
var speedUpgradeLevel = currentWeaponUpgrades.speedUpgradeLevel;
var speedUpgradeCost = currentWeaponUpgrades.speedUpgradeCost;
var damageUpgradeLevel = currentWeaponUpgrades.damageUpgradeLevel;
var damageUpgradeCost = currentWeaponUpgrades.damageUpgradeCost;
var healthUpgradeLevel = currentWeaponUpgrades.healthUpgradeLevel;
var healthUpgradeCost = currentWeaponUpgrades.healthUpgradeCost;
var maxWizardHealth = currentWeaponUpgrades.maxWizardHealth;
var wizardHealth = currentWeaponUpgrades.wizardHealth;
var fireballDamage = currentWeaponUpgrades.fireballDamage;
// Health bar UI update
function updateHealthBar() {
if (typeof healthBarFill === "undefined" || typeof healthBarBg === "undefined") return;
var ratio = Math.max(0, Math.min(1, wizardHealth / maxWizardHealth));
healthBarFill.width = (healthBarBg.width - 8) * ratio;
// Keep bar anchored left
healthBarFill.x = healthBarBg.x - (healthBarBg.width - 8) * (1 - ratio) / 2;
}
// Score variable
var score = 0;
// Persistent total coins (stacked across games)
var totalCoins = storage.totalCoins || 0;
// --- Persistent Progress: Restore on load ---
var coinCount = typeof storage.coinCount === "number" ? storage.coinCount : 0;
var speedUpgradeLevel = typeof storage.speedUpgradeLevel === "number" ? storage.speedUpgradeLevel : 0;
var speedUpgradeCost = typeof storage.speedUpgradeCost === "number" ? storage.speedUpgradeCost : 50;
var damageUpgradeLevel = typeof storage.damageUpgradeLevel === "number" ? storage.damageUpgradeLevel : 0;
var damageUpgradeCost = typeof storage.damageUpgradeCost === "number" ? storage.damageUpgradeCost : 60;
var healthUpgradeLevel = typeof storage.healthUpgradeLevel === "number" ? storage.healthUpgradeLevel : 0;
var healthUpgradeCost = typeof storage.healthUpgradeCost === "number" ? storage.healthUpgradeCost : 25;
var maxWizardHealth = typeof storage.maxWizardHealth === "number" ? storage.maxWizardHealth : 5;
var wizardHealth = typeof storage.wizardHealth === "number" ? storage.wizardHealth : maxWizardHealth;
var fireballDamage = typeof storage.fireballDamage === "number" ? storage.fireballDamage : 1;
var shopPurchases = storage.shopPurchases || {};
var wizardAsset = storage.wizardAsset || "wizard";
// Score text
var scoreText = new Text2("Score: 0", {
size: 100,
fill: "#fff"
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
// After scoreText and wizard are positioned, update startUiContainer position
if (typeof startUiContainer !== "undefined" && startUiContainer && typeof wizard !== "undefined" && wizard) {
// Place UI container between score and wizard, but not overlapping either
startUiContainer.x = 2048 / 2;
startUiContainer.y = wizard.y - 180;
}
// Coin icon and coin count text
var coinIcon = LK.getAsset('coin', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2
});
var coinText = new Text2("" + coinCount, {
size: 90,
fill: 0xFFD700
});
coinText.anchor.set(0.5, 0);
// Add coin icon and text to the GUI, but position them below the score text
LK.gui.top.addChild(coinIcon);
LK.gui.top.addChild(coinText);
// --- Health Bar UI under coin asset ---
var healthBarWidth = 245;
var healthBarHeight = 57;
var healthBarBg = LK.getAsset('background', {
anchorX: 0.5,
anchorY: 0.5,
width: healthBarWidth,
height: healthBarHeight
});
healthBarBg.alpha = 0.35;
var healthBarFill = LK.getAsset('background', {
anchorX: 0.5,
anchorY: 0.5,
width: healthBarWidth - 8,
height: healthBarHeight - 8
});
healthBarFill.alpha = 0.85;
healthBarFill.tint = 0x2ecc40;
// Add white "HEALTH" label centered in the bar
var healthBarLabel = new Text2("HEALTH", {
size: 64,
// Increased font size
fill: "#fff"
});
healthBarLabel.anchor.set(0.5, 0.5);
LK.gui.top.addChild(healthBarBg);
LK.gui.top.addChild(healthBarFill);
LK.gui.top.addChild(healthBarLabel);
// --- Ammo Bar UI below health bar ---
var ammoBarWidth = healthBarWidth;
var ammoBarHeight = 36;
var ammoBarBg = LK.getAsset('background', {
anchorX: 0.5,
anchorY: 0.5,
width: ammoBarWidth,
height: ammoBarHeight
});
ammoBarBg.alpha = 0.28;
var ammoBarFill = LK.getAsset('background', {
anchorX: 0.5,
anchorY: 0.5,
width: ammoBarWidth - 8,
height: ammoBarHeight - 8
});
ammoBarFill.alpha = 0.92;
ammoBarFill.tint = 0x3498db; // blue for ammo
// Add dynamic ammo label centered in the bar
var ammoBarLabel = new Text2("", {
size: 36,
fill: "#fff"
});
ammoBarLabel.anchor.set(0.5, 0.5);
LK.gui.top.addChild(ammoBarBg);
LK.gui.top.addChild(ammoBarFill);
LK.gui.top.addChild(ammoBarLabel);
// --- Reload Button below ammo bar ---
var reloadButtonSize = 180;
var reloadButton = new Container();
var reloadButtonBg = LK.getAsset('reload', {
anchorX: 0.5,
anchorY: 0.5,
width: reloadButtonSize,
height: reloadButtonSize
});
reloadButtonBg.alpha = 0.95;
reloadButton.addChild(reloadButtonBg);
LK.gui.top.addChild(reloadButton);
// Position reload button below ammo bar (centered), moved 850px further down (250 + 750 - 100 - 50)
reloadButton.x = ammoBarBg.x;
reloadButton.y = ammoBarBg.y + ammoBarBg.height / 2 + reloadButtonSize / 2 + 18 + 850;
// Reload logic on click/tap
reloadButton.down = function (x, y, obj) {
// Only reload if not already reloading, not shuriken, and not full
if (wizardAsset !== "shuriken" && !wizardReloading && typeof wizardAmmo !== "undefined" && typeof wizardMaxAmmo !== "undefined" && wizardAmmo < wizardMaxAmmo) {
wizardReloading = true;
if (wizardReloadTimeout) {
LK.clearTimeout(wizardReloadTimeout);
wizardReloadTimeout = null;
}
wizardReloadTimeout = LK.setTimeout(function () {
wizardAmmo = wizardMaxAmmo;
wizardReloading = false;
wizardReloadTimeout = null;
}, wizardReloadTime);
}
};
// Position coin icon and text below the score text in the start screen
coinIcon.x = scoreText.x;
coinIcon.y = scoreText.y + scoreText.height + coinIcon.height * 0.6;
// Place coinText 100px to the right and 50px above the coin icon
coinText.x = coinIcon.x + 100;
coinText.y = coinIcon.y - 50;
// Position health bar under coin asset
healthBarBg.x = coinIcon.x;
healthBarBg.y = coinIcon.y + coinIcon.height * 0.7 + healthBarHeight / 2 + 8;
healthBarFill.x = healthBarBg.x;
healthBarFill.y = healthBarBg.y;
// Center the label inside the health bar
if (typeof healthBarLabel !== "undefined") {
healthBarLabel.x = healthBarBg.x;
healthBarLabel.y = healthBarBg.y;
}
// Health bar update function
updateHealthBar();
// --- Restore wizard asset if changed (e.g. shuriken) ---
if (wizardAsset !== "wizard") {
// Remove all children to ensure only one wizard asset
for (var i = wizard.children.length - 1; i >= 0; i--) {
wizard.removeChild(wizard.children[i]);
}
var newSprite = wizard.attachAsset(wizardAsset, {
anchorX: 0.5,
anchorY: 0.5
});
}
// Helper: spawn an enemy at a random edge, moving toward wizard
function spawnEnemy() {
// Only allow certain types after certain scores
var canEnemy2 = score >= 10;
var canEnemy3 = score >= 20;
var canEnemy4 = score >= 30;
var canEnemy6 = score >= 20;
// Weighted random: 30% enemy1, 25% enemy2, 15% enemy3, 10% enemy4, 20% enemy6
// If a type is not available, its weight is 0 and weights are renormalized
var weights = [30,
// enemy1
canEnemy2 ? 25 : 0,
// enemy2
canEnemy3 ? 15 : 0,
// enemy3
canEnemy4 ? 10 : 0,
// enemy4
canEnemy6 ? 5 : 0 // enemy6 (was 20, now 5 for 5% chance)
];
var totalWeight = 0;
for (var i = 0; i < weights.length; i++) totalWeight += weights[i];
var r = Math.random() * totalWeight;
var acc = 0;
var enemyType = 1;
for (var i = 0; i < weights.length; i++) {
acc += weights[i];
if (r < acc) {
enemyType = i + 1;
break;
}
}
var enemy;
if (enemyType === 1) {
enemy = new Enemy();
} else if (enemyType === 2) {
enemy = new Enemy2();
} else if (enemyType === 3) {
enemy = new Enemy3();
} else if (enemyType === 4) {
enemy = new Enemy4();
} else if (enemyType === 5) {
enemy = new Enemy6();
}
// Randomly pick an edge: 0=top, 1=bottom, 2=left, 3=right
var edge = Math.floor(Math.random() * 4);
var ex, ey;
if (edge === 0) {
ex = Math.random() * 2048;
ey = -50;
} else if (edge === 1) {
ex = Math.random() * 2048;
ey = 2732 + 50;
} else if (edge === 2) {
ex = -50;
ey = Math.random() * 2732;
} else {
ex = 2048 + 50;
ey = Math.random() * 2732;
}
enemy.x = ex;
enemy.y = ey;
// Move toward wizard
var dir = getDirection(ex, ey, wizard.x, wizard.y, 2.5 + Math.random() * 1.5); // randomize speed a bit
enemy.vx = dir.vx;
enemy.vy = dir.vy;
enemies.push(enemy);
game.addChild(enemy);
}
// Enemy spawn timer
var enemySpawnStopped = false;
var bossSpawned = false;
var boss = null;
var enemy5Spawned = false;
var enemy5 = null;
var enemySpawnTimer = LK.setInterval(function () {
// Pause enemy spawn if boss is present and alive
if (boss && !boss.destroyed) {
return;
}
// Spawn boss at score 5
if (!bossSpawned && score >= 5) {
boss = new Boss();
boss.x = 2048 / 2;
boss.y = -120;
game.addChild(boss);
bossSpawned = true;
return;
}
// Stop enemy spawn at score 120 and spawn goblin
if (!enemySpawnStopped && score >= 120) {
enemySpawnStopped = true;
LK.clearInterval(enemySpawnTimer);
// Spawn goblin (Enemy5) at score 120, only once
if (!enemy5Spawned && (typeof enemy5EverKilled === "undefined" || !enemy5EverKilled)) {
enemy5 = new Enemy5();
// Start at a random angle on the orbit
enemy5.orbitAngle = Math.random() * Math.PI * 2;
// Place initially at correct orbit position
enemy5.x = wizard.x + Math.cos(enemy5.orbitAngle) * (enemy5.orbitRadius || 850);
enemy5.y = wizard.y + Math.sin(enemy5.orbitAngle) * (enemy5.orbitRadius || 850);
enemies.push(enemy5);
game.addChild(enemy5);
enemy5Spawned = true;
return;
}
return;
}
// Only spawn normal enemies if enemy spawn is not stopped
if (!enemySpawnStopped) {
spawnEnemy();
}
}, 1200);
// Game update: update wizard, fireballs, enemies, handle collisions, and scoring
game.update = function () {
// If game not started, only update startButton and wizard visuals
if (!gameStarted) {
// Clear fireCircle timers if present
if (typeof fireCircleInterval !== "undefined" && fireCircleInterval) {
LK.clearInterval(fireCircleInterval);
fireCircleInterval = null;
}
if (typeof fireCircleTimeout !== "undefined" && fireCircleTimeout) {
LK.clearTimeout(fireCircleTimeout);
fireCircleTimeout = null;
}
// Clear permanent fireCircles if present
if (typeof fireCircles !== "undefined") {
for (var i = fireCircles.length - 1; i >= 0; i--) {
if (fireCircles[i] && !fireCircles[i].destroyed) fireCircles[i].destroy();
}
fireCircles = [];
}
// --- Reset magazine system on game over/start screen ---
// If minigun is selected, always set to 350 ammo at new game start
if (wizardAsset === "minigun") {
wizardMaxAmmo = applyAmmoUpgradeToMaxAmmo("minigun");
wizardAmmo = wizardMaxAmmo;
tapFireCooldown = 500;
} else if (wizardAsset === "Lasergun") {
wizardMaxAmmo = applyAmmoUpgradeToMaxAmmo("Lasergun");
wizardAmmo = wizardMaxAmmo;
tapFireCooldown = 300;
} else if (wizardAsset === "shotgun") {
wizardMaxAmmo = applyAmmoUpgradeToMaxAmmo("shotgun");
wizardAmmo = wizardMaxAmmo;
tapFireCooldown = 200;
} else {
wizardMaxAmmo = applyAmmoUpgradeToMaxAmmo(wizardAsset);
wizardAmmo = wizardMaxAmmo;
}
wizardReloading = false;
if (wizardReloadTimeout) {
LK.clearTimeout(wizardReloadTimeout);
wizardReloadTimeout = null;
}
if (wizard.update) wizard.update();
// Animate start button (pulse effect)
if (typeof startButton !== "undefined" && startButton && startButton.children && startButton.children.length > 0) {
var t = LK.ticks || Date.now();
var scale = 1 + 0.06 * Math.sin(t * 0.12);
startButton.scale.x = scale;
startButton.scale.y = scale;
}
return;
}
// Update wizard
if (wizard.update) wizard.update();
// Update fireballs and remove destroyed ones
for (var i = fireballs.length - 1; i >= 0; i--) {
var fb = fireballs[i];
if (fb.update) fb.update();
if (fb.destroyed) {
fireballs.splice(i, 1);
}
}
// Update permanent fireCircles (if any)
if (typeof fireCircles !== "undefined") {
for (var i = fireCircles.length - 1; i >= 0; i--) {
var fc = fireCircles[i];
if (fc && fc.update) fc.update();
if (fc && fc.destroyed) {
fireCircles.splice(i, 1);
continue;
}
// --- FireCircle damage to enemies ---
if (fc && typeof enemies !== "undefined") {
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (!enemy || enemy.destroyed) continue;
// If enemy health is 0 or below, destroy enemy and handle rewards
if (enemy.health <= 0) {
// Spawn explosion at enemy position
var explosion = new Explosion();
explosion.x = enemy.x;
explosion.y = enemy.y;
game.addChild(explosion);
// Drop healthpack if Enemy6
if (enemy.type === 6) {
var healthpack = new Healthpack();
healthpack.x = enemy.x;
healthpack.y = enemy.y;
game.addChild(healthpack);
if (typeof healthpacks === "undefined") healthpacks = [];
healthpacks.push(healthpack);
}
// Determine coin count and plus text based on enemy type
var coinAmount = 1;
if (enemy.type === 2) coinAmount = 2;
if (enemy.type === 3) coinAmount = 3;
if (enemy.type === 4) coinAmount = 4;
if (enemy.type === 5) coinAmount = 5;
// Drop the correct number of coins
if (enemy.type === 5) {
// Drop 20 coins at goblin's position when killed
for (var cc = 0; cc < 20; cc++) {
var coin = new Coin();
coin.x = enemy.x;
coin.y = enemy.y;
coin.vx = 0;
coin.vy = 0;
coin.gravity = 0;
if (cc === 0) coin.amount = 20;
coins.push(coin);
game.addChild(coin);
}
} else {
for (var cc = 0; cc < coinAmount; cc++) {
var coin = new Coin();
coin.x = enemy.x;
coin.y = enemy.y;
coin.vx = 0;
coin.vy = 0;
coin.gravity = 0;
if (cc === 0) {
coin.amount = coinAmount;
}
coins.push(coin);
game.addChild(coin);
}
}
// Play dead sound
LK.getSound('dead').play();
// If this is Enemy5, also clear enemy5 reference so it never respawns
if (enemy.type === 5) {
// Show goblingain effect at goblin's position
var goblingain = LK.getAsset('goblingain', {
anchorX: 0.5,
anchorY: 0.5,
x: enemy.x,
y: enemy.y,
scaleX: 1.0,
scaleY: 1.0,
alpha: 1
});
game.addChild(goblingain);
// Animate goblingain: scale up and fade out over 0.7s (42 frames)
(function (gobObj) {
var frames = 42,
frame = 0;
gobObj.update = function () {
frame++;
gobObj.scale.x = 1.0 + 0.5 * (frame / frames);
gobObj.scale.y = 1.0 + 0.5 * (frame / frames);
gobObj.alpha = 1 - frame / frames;
if (frame >= frames) {
gobObj.destroy();
}
};
})(goblingain);
// Mark goblin as permanently killed
enemy5EverKilled = true;
if (typeof enemy5 !== "undefined" && enemy5 === enemy) {
enemy5 = null;
enemy5Spawned = false; // Allow normal enemies to spawn again
}
// Resume normal enemy spawn if it was paused for goblin
// (Handled by enemySpawnTimer logic: normal enemies spawn if enemy5 is null or destroyed)
}
enemy.destroy();
enemies.splice(j, 1);
score += 1;
scoreText.setText("Score: " + score);
}
}
}
}
}
// Update coins and remove destroyed ones
for (var c = coins.length - 1; c >= 0; c--) {
var coin = coins[c];
// Move coin directly toward wizard
var dx = wizard.x - coin.x;
var dy = wizard.y - coin.y;
var dist = Math.sqrt(dx * dx + dy * dy);
var speed = 22; // Fast enough to feel instant, but visible
if (dist > 1) {
coin.x += dx / dist * Math.min(speed, dist);
coin.y += dy / dist * Math.min(speed, dist);
} else {
coin.x = wizard.x;
coin.y = wizard.y;
}
// Check collision with wizard (collect coin)
if (coin.lastWasIntersecting === undefined) coin.lastWasIntersecting = false;
var coinIntersecting = coin.intersects(wizard);
if (!coin.lastWasIntersecting && coinIntersecting) {
// Do not add to score when collecting coin
coinCount += 1;
coinText.setText("" + coinCount);
// Save coin count persistently
storage.coinCount = coinCount;
// Create gain effect (use gain asset instead of explosion)
var gainEffect = LK.getAsset('gain', {
anchorX: 0.5,
anchorY: 0.5,
x: coin.x,
y: coin.y,
scaleX: 1,
scaleY: 1,
alpha: 1
});
game.addChild(gainEffect);
// Animate gain effect: scale up and fade out, then destroy
(function (effect) {
var frames = 24;
var frame = 0;
effect.update = function () {
frame++;
effect.scale.x = 1 + 0.5 * (frame / frames);
effect.scale.y = 1 + 0.5 * (frame / frames);
effect.alpha = 1 - frame / frames;
if (frame >= frames) {
effect.destroy();
}
};
})(gainEffect);
// Create +N asset effect at wizard position
var plusAmount = 1;
if (coin.hasOwnProperty('amount')) {
plusAmount = coin.amount;
}
var plusText = new Text2("+" + plusAmount, {
size: 90,
fill: 0xFFD700
});
plusText.anchor.set(0.5, 0.5);
plusText.x = wizard.x;
plusText.y = wizard.y;
game.addChild(plusText);
// Animate +N asset: move up and fade out, then destroy
(function (txt) {
var startY = txt.y;
var frames = 36;
var frame = 0;
txt.alpha = 1;
txt.update = function () {
frame++;
txt.y = startY - frame * 2.2;
txt.alpha = 1 - frame / frames;
if (frame >= frames) {
txt.destroy();
}
};
})(plusText);
// Remove coin
coin.destroy();
coins.splice(c, 1);
continue;
}
coin.lastWasIntersecting = coinIntersecting;
}
// --- Healthpack update and collection ---
if (typeof healthpacks === "undefined") healthpacks = [];
for (var h = healthpacks.length - 1; h >= 0; h--) {
var hp = healthpacks[h];
if (hp.update) hp.update();
if (hp.destroyed) {
healthpacks.splice(h, 1);
continue;
}
if (hp.lastWasIntersecting === undefined) hp.lastWasIntersecting = false;
var hpIntersecting = hp.intersects(wizard);
if (!hp.lastWasIntersecting && hpIntersecting) {
// Restore 2 wizard health, up to max
wizardHealth = Math.min(maxWizardHealth, wizardHealth + 2);
storage.wizardHealth = wizardHealth;
updateHealthBar();
// Flash wizard green for feedback
if (wizard.children && wizard.children.length > 0) {
LK.effects.flashObject(wizard.children[0], 0x2ecc40, 400);
}
// Show health gain effect
var healthGain = LK.getAsset('health', {
anchorX: 0.5,
anchorY: 0.5,
x: wizard.x,
y: wizard.y,
scaleX: 1,
scaleY: 1,
alpha: 1
});
game.addChild(healthGain);
(function (effect) {
var frames = 24;
var frame = 0;
effect.update = function () {
frame++;
effect.scale.x = 1 + 0.5 * (frame / frames);
effect.scale.y = 1 + 0.5 * (frame / frames);
effect.alpha = 1 - frame / frames;
if (frame >= frames) {
effect.destroy();
}
};
})(healthGain);
// Show "+2" text
var plus2 = new Text2("+2", {
size: 90,
fill: 0x2ecc40
});
plus2.anchor.set(0.5, 0.5);
plus2.x = wizard.x;
plus2.y = wizard.y;
game.addChild(plus2);
(function (txt) {
var startY = txt.y;
var frames = 36;
var frame = 0;
txt.alpha = 1;
txt.update = function () {
frame++;
txt.y = startY - frame * 2.2;
txt.alpha = 1 - frame / frames;
if (frame >= frames) {
txt.destroy();
}
};
})(plus2);
// Remove healthpack
hp.destroy();
healthpacks.splice(h, 1);
continue;
}
hp.lastWasIntersecting = hpIntersecting;
}
// Position coin icon and text below the score text (centered)
if (scoreText.parent && coinIcon.parent && coinText.parent) {
// Place coin icon below the score text, centered
coinIcon.x = scoreText.x;
coinIcon.y = scoreText.y + scoreText.height + coinIcon.height * 0.6;
// Place coinText 100px to the right and 50px above the coin icon
coinText.x = coinIcon.x + 100;
coinText.y = coinIcon.y - 50;
// Position health bar under coin asset
if (typeof healthBarBg !== "undefined" && typeof healthBarFill !== "undefined") {
healthBarBg.x = coinIcon.x;
healthBarBg.y = coinIcon.y + coinIcon.height * 0.7 + healthBarBg.height / 2 + 8;
healthBarFill.x = healthBarBg.x - (healthBarBg.width - 8) * (1 - Math.max(0, Math.min(1, wizardHealth / maxWizardHealth))) / 2;
healthBarFill.y = healthBarBg.y;
// Keep label centered in bar
if (typeof healthBarLabel !== "undefined") {
healthBarLabel.x = healthBarBg.x;
healthBarLabel.y = healthBarBg.y;
}
}
updateHealthBar();
// --- Position and update ammo bar below health bar ---
if (typeof ammoBarBg !== "undefined" && typeof ammoBarFill !== "undefined") {
ammoBarBg.x = healthBarBg.x;
ammoBarBg.y = healthBarBg.y + healthBarBg.height / 2 + ammoBarBg.height / 2 + 10;
ammoBarFill.x = ammoBarBg.x;
ammoBarFill.y = ammoBarBg.y;
if (typeof ammoBarLabel !== "undefined") {
ammoBarLabel.x = ammoBarBg.x;
ammoBarLabel.y = ammoBarBg.y;
// Update ammo label text
if (wizardAsset === "shuriken") {
ammoBarLabel.setText("∞/∞");
} else if (typeof wizardAmmo !== "undefined" && typeof wizardMaxAmmo !== "undefined") {
ammoBarLabel.setText(wizardAmmo + "/" + wizardMaxAmmo);
} else {
ammoBarLabel.setText("");
}
}
// Update ammo bar fill width
var ammoRatio = 1;
if (wizardAsset === "shuriken") {
ammoRatio = 1; // always full for shuriken
} else if (typeof wizardAmmo !== "undefined" && typeof wizardMaxAmmo !== "undefined" && wizardMaxAmmo > 0) {
ammoRatio = Math.max(0, Math.min(1, wizardAmmo / wizardMaxAmmo));
}
ammoBarFill.width = (ammoBarBg.width - 8) * ammoRatio;
ammoBarFill.x = ammoBarBg.x - (ammoBarBg.width - 8) * (1 - ammoRatio) / 2;
}
}
// Update enemies and remove destroyed ones
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (enemy.update) enemy.update();
if (enemy.destroyed) {
enemies.splice(j, 1);
continue;
}
// ... (rest of enemy collision code unchanged)
// Check collision with wizard (health system)
if (enemy.lastWasIntersecting === undefined) enemy.lastWasIntersecting = false;
var nowIntersecting = enemy.intersects(wizard);
if (!enemy.lastWasIntersecting && nowIntersecting) {
// Only decrease health if not already at 0
if (wizardHealth > 0) {
wizardHealth -= 1;
// Save wizard health
storage.wizardHealth = wizardHealth;
// Flash wizard red
if (wizard.children && wizard.children.length > 0) {
LK.effects.flashObject(wizard.children[0], 0xff0000, 400);
}
// Update health bar (no-op)
updateHealthBar();
// Remove enemy after hit
// If this is Enemy5, also clear enemy5 reference so it never respawns
if (enemy.type === 5) {
if (typeof enemy5 !== "undefined" && enemy5 === enemy) {
enemy5 = null;
}
}
enemy.destroy();
enemies.splice(j, 1);
// If health reaches 0, trigger game over
if (wizardHealth <= 0) {
totalCoins += coinCount;
storage.totalCoins = totalCoins;
LK.effects.flashScreen(0xff0000, 1000);
// Instead of game over, reset to start screen
gameStarted = false;
// Recreate start UI if needed
if (!startUiContainer || startUiContainer.destroyed) {
startUiContainer = new Container();
startButton = new Container();
startButtonBg = LK.getAsset('background', {
anchorX: 0.5,
anchorY: 0.5,
width: startButtonWidth,
height: startButtonHeight,
color: 0x1e90ff
});
startButtonBg.alpha = 0.92;
startButton.addChild(startButtonBg);
startButtonText = new Text2("START GAME", {
size: 220,
fill: "#fff"
});
startButtonText.anchor.set(0.5, 0.5);
startButtonText.x = 0;
startButtonText.y = -120;
startButton.addChild(startButtonText);
upgradeButton = new Container();
upgradeButtonBg = LK.getAsset('background', {
anchorX: 0.5,
anchorY: 0.5,
width: upgradeButtonWidth,
height: upgradeButtonHeight,
color: 0x2ecc71
});
upgradeButtonBg.alpha = 0.92;
upgradeButton.addChild(upgradeButtonBg);
upgradeButtonText = new Text2("UPGRADE", {
size: 110,
// Half of recreated START GAME (220)
fill: "#fff"
});
upgradeButtonText.anchor.set(0.5, 0.5);
upgradeButtonText.x = 0;
upgradeButtonText.y = 0;
upgradeButton.addChild(upgradeButtonText);
startButton.x = 0;
startButton.y = -400;
upgradeButton.x = 0;
upgradeButton.y = startButton.y + startButtonHeight / 2 + 55 + upgradeButtonHeight / 2;
startUiContainer.addChild(startButton);
startUiContainer.addChild(upgradeButton);
startUiContainer.x = 2048 / 2;
startUiContainer.y = 2732 / 2;
game.addChild(startUiContainer);
// Re-attach handlers
upgradeButton.down = function (x, y, obj) {
if (upgradeWindow && !upgradeWindow.destroyed) return;
showUpgradeWindow();
};
startButton.down = function (x, y, obj) {
var now = Date.now();
if (now - lastTapFireTime < tapFireCooldown) {
// Too soon, ignore this tap for firing
return;
}
lastTapFireTime = now;
if (gameStarted) return;
gameStarted = true;
if (startUiContainer && !startUiContainer.destroyed) {
startUiContainer.destroy();
}
for (var i = enemies.length - 1; i >= 0; i--) {
if (enemies[i] && !enemies[i].destroyed) enemies[i].destroy();
enemies.splice(i, 1);
}
for (var i = fireballs.length - 1; i >= 0; i--) {
if (fireballs[i] && !fireballs[i].destroyed) fireballs[i].destroy();
fireballs.splice(i, 1);
}
for (var i = coins.length - 1; i >= 0; i--) {
if (coins[i] && !coins[i].destroyed) coins[i].destroy();
coins.splice(i, 1);
}
score = 0;
// coinCount is NOT reset here, so coins are preserved when starting a new game
scoreText.setText("Score: 0");
coinText.setText("" + coinCount);
wizard.x = 2048 / 2;
wizard.y = 2732 / 2;
// Load upgrades for selected weapon
currentWeaponUpgrades = getWeaponUpgrades(wizardAsset);
speedUpgradeLevel = currentWeaponUpgrades.speedUpgradeLevel;
speedUpgradeCost = currentWeaponUpgrades.speedUpgradeCost;
damageUpgradeLevel = currentWeaponUpgrades.damageUpgradeLevel;
damageUpgradeCost = currentWeaponUpgrades.damageUpgradeCost;
healthUpgradeLevel = currentWeaponUpgrades.healthUpgradeLevel;
healthUpgradeCost = currentWeaponUpgrades.healthUpgradeCost;
maxWizardHealth = currentWeaponUpgrades.maxWizardHealth;
wizardHealth = currentWeaponUpgrades.wizardHealth;
fireballDamage = currentWeaponUpgrades.fireballDamage;
// Remove all children to ensure only one wizard asset
for (var i = wizard.children.length - 1; i >= 0; i--) {
wizard.removeChild(wizard.children[i]);
}
// Attach wizard asset if not present
var hasWizardSprite = false;
for (var i = 0; i < wizard.children.length; i++) {
hasWizardSprite = true;
break;
}
if (!hasWizardSprite) {
var newSprite = wizard.attachAsset(wizardAsset, {
anchorX: 0.5,
anchorY: 0.5
});
if (newSprite) {
newSprite.rotation = Math.PI;
}
} else if (wizard.children && wizard.children.length > 0) {
wizard.children[0].rotation = Math.PI;
}
// Switch upgrades to selected weapon on restart
currentWeaponUpgrades = getWeaponUpgrades(wizardAsset);
speedUpgradeLevel = currentWeaponUpgrades.speedUpgradeLevel;
speedUpgradeCost = currentWeaponUpgrades.speedUpgradeCost;
damageUpgradeLevel = currentWeaponUpgrades.damageUpgradeLevel;
damageUpgradeCost = currentWeaponUpgrades.damageUpgradeCost;
healthUpgradeLevel = currentWeaponUpgrades.healthUpgradeLevel;
healthUpgradeCost = currentWeaponUpgrades.healthUpgradeCost;
maxWizardHealth = currentWeaponUpgrades.maxWizardHealth;
wizardHealth = currentWeaponUpgrades.wizardHealth;
fireballDamage = currentWeaponUpgrades.fireballDamage;
wizardHealth = maxWizardHealth;
storage.wizardHealth = wizardHealth;
storage.maxWizardHealth = maxWizardHealth;
storage.wizardHealth = wizardHealth;
storage.maxWizardHealth = maxWizardHealth;
updateHealthBar();
game.move = originalGameMove;
game.down = originalGameDown;
game.up = originalGameUp;
};
} else {
// If UI exists, just re-add it
if (startUiContainer.parent !== game) {
game.addChild(startUiContainer);
}
// Recreate shop button and handlers if needed
if (typeof shopButton === "undefined" || !shopButton || shopButton.destroyed) {
// --- SHOP BUTTON UI LOGIC (recreate) ---
shopButton = new Container();
shopButtonBg = LK.getAsset('background', {
anchorX: 0.5,
anchorY: 0.5,
width: shopButtonWidth,
height: shopButtonHeight
});
shopButtonBg.alpha = 0.92;
shopButton.addChild(shopButtonBg);
shopButtonText = new Text2("SHOP", {
size: 110,
fill: "#fff"
});
shopButtonText.anchor.set(0.5, 0.5);
shopButtonText.x = 0;
shopButtonText.y = 0;
shopButton.addChild(shopButtonText);
shopButton.x = 0;
shopButton.y = upgradeButton.y + upgradeButtonHeight / 2 + 40 + shopButtonHeight / 2;
startUiContainer.addChild(shopButton);
shopButton.down = function (x, y, obj) {
if (shopWindow && !shopWindow.destroyed) return;
showShopWindow();
};
}
}
// Block input until start is pressed
blockGameInput();
return;
}
}
}
enemy.lastWasIntersecting = nowIntersecting;
// Check collision with fireballs
for (var k = fireballs.length - 1; k >= 0; k--) {
var fb = fireballs[k];
if (enemy['fb' + k + '_lastIntersecting'] === undefined) enemy['fb' + k + '_lastIntersecting'] = false;
var fbIntersect = enemy.intersects(fb);
// Only allow collision if fireball is inside the visible screen
var fireballOnScreen = fb.x >= 0 && fb.x <= 2048 && fb.y >= 0 && fb.y <= 2732;
if (!enemy['fb' + k + '_lastIntersecting'] && fbIntersect && fireballOnScreen) {
// Decrease enemy health by fireballDamage (default 1, upgrades increase)
// Award 1 coin for each fireball hit on goblin (not killed)
if (enemy.type === 5 && enemy.health > 0) {
// Drop 1 coin at goblin's position
var coin = new Coin();
coin.x = enemy.x;
coin.y = enemy.y;
coin.vx = 0;
coin.vy = 0;
coin.gravity = 0;
coin.amount = 1;
coins.push(coin);
game.addChild(coin);
}
enemy.health -= fireballDamage;
// Destroy fireball
fb.destroy();
fireballs.splice(k, 1);
// If enemy health reaches 0, destroy enemy and increase score
if (enemy.health <= 0) {
// Spawn explosion at enemy position
var explosion = new Explosion();
explosion.x = enemy.x;
explosion.y = enemy.y;
game.addChild(explosion);
// Drop healthpack if Enemy6
if (enemy.type === 6) {
var healthpack = new Healthpack();
healthpack.x = enemy.x;
healthpack.y = enemy.y;
game.addChild(healthpack);
if (typeof healthpacks === "undefined") healthpacks = [];
healthpacks.push(healthpack);
}
// Determine coin count and plus text based on enemy type
var coinAmount = 1;
if (enemy.type === 2) coinAmount = 2;
if (enemy.type === 3) coinAmount = 3;
if (enemy.type === 4) coinAmount = 4;
if (enemy.type === 5) coinAmount = 5;
// Drop the correct number of coins
if (enemy.type === 5) {
// Drop 20 coins at goblin's position when killed
for (var cc = 0; cc < 20; cc++) {
var coin = new Coin();
coin.x = enemy.x;
coin.y = enemy.y;
coin.vx = 0;
coin.vy = 0;
coin.gravity = 0;
if (cc === 0) coin.amount = 20;
coins.push(coin);
game.addChild(coin);
}
} else {
for (var cc = 0; cc < coinAmount; cc++) {
var coin = new Coin();
coin.x = enemy.x;
coin.y = enemy.y;
coin.vx = 0;
coin.vy = 0;
coin.gravity = 0;
// For multi-coin drops, only the first coin will show +N at wizard
if (cc === 0) {
coin.amount = coinAmount;
}
coins.push(coin);
game.addChild(coin);
}
}
// Play dead sound
LK.getSound('dead').play();
// If this is Enemy5, also clear enemy5 reference so it never respawns
if (enemy.type === 5) {
// Show goblingain effect at goblin's position
var goblingain = LK.getAsset('goblingain', {
anchorX: 0.5,
anchorY: 0.5,
x: enemy.x,
y: enemy.y,
scaleX: 1.0,
scaleY: 1.0,
alpha: 1
});
game.addChild(goblingain);
// Animate goblingain: scale up and fade out over 0.7s (42 frames)
(function (gobObj) {
var frames = 42,
frame = 0;
gobObj.update = function () {
frame++;
gobObj.scale.x = 1.0 + 0.5 * (frame / frames);
gobObj.scale.y = 1.0 + 0.5 * (frame / frames);
gobObj.alpha = 1 - frame / frames;
if (frame >= frames) {
gobObj.destroy();
}
};
})(goblingain);
// Mark goblin as permanently killed
enemy5EverKilled = true;
if (typeof enemy5 !== "undefined" && enemy5 === enemy) {
enemy5 = null;
enemy5Spawned = false; // Allow normal enemies to spawn again
}
// Resume normal enemy spawn if it was paused for goblin
// (Handled by enemySpawnTimer logic: normal enemies spawn if enemy5 is null or destroyed)
}
enemy.destroy();
enemies.splice(j, 1);
score += 1;
scoreText.setText("Score: " + score);
// (Removed: +N effect at enemy death. Now shown at wizard when coin is collected)
break;
}
}
enemy['fb' + k + '_lastIntersecting'] = fbIntersect;
}
}
// --- Boss update and boss fireball collision ---
if (boss && !boss.destroyed) {
if (boss.update) boss.update();
// Boss hit by fireballs
for (var k = fireballs.length - 1; k >= 0; k--) {
var fb = fireballs[k];
if (boss['fb' + k + '_lastIntersecting'] === undefined) boss['fb' + k + '_lastIntersecting'] = false;
var fbIntersect = boss.intersects(fb);
// Only allow collision if fireball is inside the visible screen
var fireballOnScreen = fb.x >= 0 && fb.x <= 2048 && fb.y >= 0 && fb.y <= 2732;
if (!boss['fb' + k + '_lastIntersecting'] && fbIntersect && fireballOnScreen) {
boss.health -= fireballDamage;
fb.destroy();
fireballs.splice(k, 1);
// Flash boss on hit
if (boss.children && boss.children.length > 0) {
LK.effects.flashObject(boss.children[0], 0xff0000, 200);
}
// Boss death
if (boss.health <= 0) {
// Spawn explosion at boss position
var explosion = new Explosion();
explosion.x = boss.x;
explosion.y = boss.y;
game.addChild(explosion);
// Drop 10 coins
for (var cc = 0; cc < 10; cc++) {
var coin = new Coin();
coin.x = boss.x;
coin.y = boss.y;
coin.vx = 0;
coin.vy = 0;
coin.gravity = 0;
if (cc === 0) coin.amount = 10;
coins.push(coin);
game.addChild(coin);
}
LK.getSound('dead').play();
boss.destroy();
boss = null;
// Clean up all bossBullets after boss death
for (var bb = bossBullets.length - 1; bb >= 0; bb--) {
if (bossBullets[bb] && !bossBullets[bb].destroyed) bossBullets[bb].destroy();
bossBullets.splice(bb, 1);
}
// Award 10 score for boss
score += 10;
scoreText.setText("Score: " + score);
// --- Show UI with two buttons: Slow Timer and Fireball ---
if (typeof bossRewardUi !== "undefined" && bossRewardUi && !bossRewardUi.destroyed) {
bossRewardUi.destroy();
}
bossRewardUi = new Container();
// Background
var rewardBg = LK.getAsset('background', {
anchorX: 0.5,
anchorY: 0.5,
width: 900,
height: 600
});
rewardBg.alpha = 0.98;
bossRewardUi.addChild(rewardBg);
// Title
var rewardTitle = new Text2("Choose Your Reward!", {
size: 110,
fill: "#fff"
});
rewardTitle.anchor.set(0.5, 0.5);
rewardTitle.x = 0;
rewardTitle.y = -180;
bossRewardUi.addChild(rewardTitle);
// Slow Timer Button
var slowBtn = new Container();
var slowBtnBg = LK.getAsset('background', {
anchorX: 0.5,
anchorY: 0.5,
width: 340,
height: 140
});
slowBtnBg.alpha = 0.93;
slowBtn.addChild(slowBtnBg);
// Use timer asset instead of text
var slowBtnIcon = LK.getAsset('timer', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.1,
scaleY: 1.1,
x: 0,
y: 0
});
slowBtn.addChild(slowBtnIcon);
slowBtn.x = -200;
slowBtn.y = 80;
bossRewardUi.addChild(slowBtn);
// Fireball Button
var fireballBtn = new Container();
var fireballBtnBg = LK.getAsset('background', {
anchorX: 0.5,
anchorY: 0.5,
width: 340,
height: 140
});
fireballBtnBg.alpha = 0.93;
fireballBtn.addChild(fireballBtnBg);
// Use firecircle asset instead of text
var fireballBtnIcon = LK.getAsset('firecircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.1,
scaleY: 1.1,
x: 0,
y: 0
});
fireballBtn.addChild(fireballBtnIcon);
fireballBtn.x = 200;
fireballBtn.y = 80;
bossRewardUi.addChild(fireballBtn);
// Center UI
bossRewardUi.x = 2048 / 2;
bossRewardUi.y = 2732 / 2;
game.addChild(bossRewardUi);
// Pause enemy spawn until a button is pressed
enemySpawnStopped = true;
if (enemySpawnTimer) LK.clearInterval(enemySpawnTimer);
// Button handlers: resume game and remove UI
var resumeAfterReward = function resumeAfterReward() {
if (bossRewardUi && !bossRewardUi.destroyed) {
bossRewardUi.destroy();
bossRewardUi = null;
}
// Resume enemy spawn at double frequency
enemySpawnStopped = false;
if (enemySpawnTimer) LK.clearInterval(enemySpawnTimer);
enemySpawnTimer = LK.setInterval(function () {
// Pause enemy spawn if boss is present and alive
if (boss && !boss.destroyed) {
return;
}
if (!enemySpawnStopped) {
spawnEnemy();
}
}, 600); // 1200/2 = 600ms (double frequency)
};
slowBtn.down = function (x, y, obj) {
// (Effect will be implemented later)
resumeAfterReward();
};
fireballBtn.down = function (x, y, obj) {
// FireCircle reward: spawn a single permanent, rotating firecircle
resumeAfterReward();
// Remove any previous firecircle timers
if (typeof fireCircleInterval !== "undefined" && fireCircleInterval) {
LK.clearInterval(fireCircleInterval);
fireCircleInterval = null;
}
if (typeof fireCircleTimeout !== "undefined" && fireCircleTimeout) {
LK.clearTimeout(fireCircleTimeout);
fireCircleTimeout = null;
}
// Remove any existing firecircles
if (typeof fireCircles === "undefined") fireCircles = [];
for (var i = fireCircles.length - 1; i >= 0; i--) {
if (fireCircles[i] && !fireCircles[i].destroyed) fireCircles[i].destroy();
fireCircles.splice(i, 1);
}
// Spawn a single permanent FireCircle
var fc = new FireCircle();
fc.orbitAngle = Math.random() * Math.PI * 2;
if (typeof wizard !== "undefined" && wizard && !wizard.destroyed) {
fc.centerX = wizard.x;
fc.centerY = wizard.y;
}
game.addChild(fc);
fireCircles.push(fc);
};
break;
}
}
boss['fb' + k + '_lastIntersecting'] = fbIntersect;
}
// --- BossBullet update, collision with wizard and fireballs ---
}
// Update bossBullets
for (var b = bossBullets.length - 1; b >= 0; b--) {
var bullet = bossBullets[b];
if (bullet.update) bullet.update();
if (bullet.destroyed) {
bossBullets.splice(b, 1);
continue;
}
// Collision with wizard
if (bullet.lastWasIntersecting === undefined) bullet.lastWasIntersecting = false;
var bulletIntersecting = bullet.intersects(wizard);
if (!bullet.lastWasIntersecting && bulletIntersecting) {
// Wizard takes 1 damage
if (wizardHealth > 0) {
wizardHealth -= 1;
storage.wizardHealth = wizardHealth;
if (wizard.children && wizard.children.length > 0) {
LK.effects.flashObject(wizard.children[0], 0xff0000, 400);
}
updateHealthBar();
// If health reaches 0, trigger game over and return to main screen
if (wizardHealth <= 0) {
totalCoins += coinCount;
storage.totalCoins = totalCoins;
LK.effects.flashScreen(0xff0000, 1000);
gameStarted = false;
// Recreate start UI if needed
if (!startUiContainer || startUiContainer.destroyed) {
startUiContainer = new Container();
startButton = new Container();
startButtonBg = LK.getAsset('background', {
anchorX: 0.5,
anchorY: 0.5,
width: startButtonWidth,
height: startButtonHeight,
color: 0x1e90ff
});
startButtonBg.alpha = 0.92;
startButton.addChild(startButtonBg);
startButtonText = new Text2("START GAME", {
size: 220,
fill: "#fff"
});
startButtonText.anchor.set(0.5, 0.5);
startButtonText.x = 0;
startButtonText.y = -120;
startButton.addChild(startButtonText);
upgradeButton = new Container();
upgradeButtonBg = LK.getAsset('background', {
anchorX: 0.5,
anchorY: 0.5,
width: upgradeButtonWidth,
height: upgradeButtonHeight,
color: 0x2ecc71
});
upgradeButtonBg.alpha = 0.92;
upgradeButton.addChild(upgradeButtonBg);
upgradeButtonText = new Text2("UPGRADE", {
size: 110,
// Half of recreated START GAME (220)
fill: "#fff"
});
upgradeButtonText.anchor.set(0.5, 0.5);
upgradeButtonText.x = 0;
upgradeButtonText.y = 0;
upgradeButton.addChild(upgradeButtonText);
startButton.x = 0;
startButton.y = -400;
upgradeButton.x = 0;
upgradeButton.y = startButton.y + startButtonHeight / 2 + 55 + upgradeButtonHeight / 2;
startUiContainer.addChild(startButton);
startUiContainer.addChild(upgradeButton);
startUiContainer.x = 2048 / 2;
startUiContainer.y = 2732 / 2;
game.addChild(startUiContainer);
// Re-attach handlers
upgradeButton.down = function (x, y, obj) {
if (upgradeWindow && !upgradeWindow.destroyed) return;
showUpgradeWindow();
};
startButton.down = function (x, y, obj) {
var now = Date.now();
if (now - lastTapFireTime < tapFireCooldown) {
// Too soon, ignore this tap for firing
return;
}
lastTapFireTime = now;
if (gameStarted) return;
gameStarted = true;
if (startUiContainer && !startUiContainer.destroyed) {
startUiContainer.destroy();
}
for (var i = enemies.length - 1; i >= 0; i--) {
if (enemies[i] && !enemies[i].destroyed) enemies[i].destroy();
enemies.splice(i, 1);
}
for (var i = fireballs.length - 1; i >= 0; i--) {
if (fireballs[i] && !fireballs[i].destroyed) fireballs[i].destroy();
fireballs.splice(i, 1);
}
for (var i = coins.length - 1; i >= 0; i--) {
if (coins[i] && !coins[i].destroyed) coins[i].destroy();
coins.splice(i, 1);
}
score = 0;
// coinCount is NOT reset here, so coins are preserved when starting a new game
scoreText.setText("Score: 0");
coinText.setText("" + coinCount);
wizard.x = 2048 / 2;
wizard.y = 2732 / 2;
// Load upgrades for selected weapon
currentWeaponUpgrades = getWeaponUpgrades(wizardAsset);
speedUpgradeLevel = currentWeaponUpgrades.speedUpgradeLevel;
speedUpgradeCost = currentWeaponUpgrades.speedUpgradeCost;
damageUpgradeLevel = currentWeaponUpgrades.damageUpgradeLevel;
damageUpgradeCost = currentWeaponUpgrades.damageUpgradeCost;
healthUpgradeLevel = currentWeaponUpgrades.healthUpgradeLevel;
healthUpgradeCost = currentWeaponUpgrades.healthUpgradeCost;
maxWizardHealth = currentWeaponUpgrades.maxWizardHealth;
wizardHealth = currentWeaponUpgrades.wizardHealth;
fireballDamage = currentWeaponUpgrades.fireballDamage;
// Remove all children to ensure only one wizard asset
for (var i = wizard.children.length - 1; i >= 0; i--) {
wizard.removeChild(wizard.children[i]);
}
// Attach wizard asset if not present
var hasWizardSprite = false;
for (var i = 0; i < wizard.children.length; i++) {
hasWizardSprite = true;
break;
}
if (!hasWizardSprite) {
var newSprite = wizard.attachAsset(wizardAsset, {
anchorX: 0.5,
anchorY: 0.5
});
if (newSprite) {
newSprite.rotation = Math.PI;
}
} else if (wizard.children && wizard.children.length > 0) {
wizard.children[0].rotation = Math.PI;
}
// Switch upgrades to selected weapon on restart
currentWeaponUpgrades = getWeaponUpgrades(wizardAsset);
speedUpgradeLevel = currentWeaponUpgrades.speedUpgradeLevel;
speedUpgradeCost = currentWeaponUpgrades.speedUpgradeCost;
damageUpgradeLevel = currentWeaponUpgrades.damageUpgradeLevel;
damageUpgradeCost = currentWeaponUpgrades.damageUpgradeCost;
healthUpgradeLevel = currentWeaponUpgrades.healthUpgradeLevel;
healthUpgradeCost = currentWeaponUpgrades.healthUpgradeCost;
maxWizardHealth = currentWeaponUpgrades.maxWizardHealth;
wizardHealth = currentWeaponUpgrades.wizardHealth;
fireballDamage = currentWeaponUpgrades.fireballDamage;
wizardHealth = maxWizardHealth;
storage.wizardHealth = wizardHealth;
storage.maxWizardHealth = maxWizardHealth;
storage.wizardHealth = wizardHealth;
storage.maxWizardHealth = maxWizardHealth;
updateHealthBar();
game.move = originalGameMove;
game.down = originalGameDown;
game.up = originalGameUp;
};
} else {
// If UI exists, just re-add it
if (startUiContainer.parent !== game) {
game.addChild(startUiContainer);
}
// Recreate shop button and handlers if needed
if (typeof shopButton === "undefined" || !shopButton || shopButton.destroyed) {
// --- SHOP BUTTON UI LOGIC (recreate) ---
shopButton = new Container();
shopButtonBg = LK.getAsset('background', {
anchorX: 0.5,
anchorY: 0.5,
width: shopButtonWidth,
height: shopButtonHeight
});
shopButtonBg.alpha = 0.92;
shopButton.addChild(shopButtonBg);
shopButtonText = new Text2("SHOP", {
size: 110,
fill: "#fff"
});
shopButtonText.anchor.set(0.5, 0.5);
shopButtonText.x = 0;
shopButtonText.y = 0;
shopButton.addChild(shopButtonText);
shopButton.x = 0;
shopButton.y = upgradeButton.y + upgradeButtonHeight / 2 + 40 + shopButtonHeight / 2;
startUiContainer.addChild(shopButton);
shopButton.down = function (x, y, obj) {
if (shopWindow && !shopWindow.destroyed) return;
showShopWindow();
};
}
}
// Block input until start is pressed
blockGameInput();
return;
}
}
// Destroy bullet
bullet.destroy();
bossBullets.splice(b, 1);
// If health reaches 0, trigger game over (handled above)
continue;
}
bullet.lastWasIntersecting = bulletIntersecting;
// Collision with fireballs
for (var k = fireballs.length - 1; k >= 0; k--) {
var fb = fireballs[k];
if (bullet['fb' + k + '_lastIntersecting'] === undefined) bullet['fb' + k + '_lastIntersecting'] = false;
var fbIntersect = bullet.intersects(fb);
var fireballOnScreen = fb.x >= 0 && fb.x <= 2048 && fb.y >= 0 && fb.y <= 2732;
if (!bullet['fb' + k + '_lastIntersecting'] && fbIntersect && fireballOnScreen) {
bullet.health -= fireballDamage;
fb.destroy();
fireballs.splice(k, 1);
// Flash bullet on hit
if (bullet.children && bullet.children.length > 0) {
LK.effects.flashObject(bullet.children[0], 0xff0000, 200);
}
// If bullet destroyed, spawn explosion and remove
if (bullet.health <= 0) {
var explosion = new Explosion();
explosion.x = bullet.x;
explosion.y = bullet.y;
game.addChild(explosion);
bullet.destroy();
bossBullets.splice(b, 1);
break;
}
}
bullet['fb' + k + '_lastIntersecting'] = fbIntersect;
}
}
}; ===================================================================
--- original.js
+++ change.js
@@ -483,9 +483,9 @@
});
// Orbit parameters
self.orbitRadius = 850;
self.orbitAngle = 0;
- self.orbitSpeed = 0.018; // Fast enough to sweep the area
+ self.orbitSpeed = 0.009; // Yarı yarıya yavaşlatıldı (half speed)
self.centerX = 2048 / 2;
self.centerY = 2732 / 2;
self.damage = 2; // FireCircle now deals 2 damage per hit
self.enemiesHit = {}; // Track which enemies have been hit this frame
get an enemy in the form of slime. In-Game asset. 2d. High contrast. No shadows
get an enemy in the form of slime. In-Game asset. 2d. High contrast. No shadows
Let there be a mini machine gun and let this gun be pixel shaped. In-Game asset. 2d. High contrast. No shadows
a bullet but yellow and pixel. In-Game asset. 2d. High contrast. No shadows
slime explosion. In-Game asset. 2d. High contrast. No shadows
Change eyes like red
+ gain coin effect. In-Game asset. 2d. High contrast. No shadows
Fast bullet upgrade. In-Game asset. 2d. High contrast. No shadows
Upgrade power bullet. In-Game asset. 2d. High contrast. No shadows
Health + icon pixels. In-Game asset. 2d. High contrast. No shadows
Handgun pixel its look left. In-Game asset. 2d. High contrast. No shadows
işaretli alanı siyaha boya
pixel shuriken but 8 edges. In-Game asset. 2d. High contrast. No shadows
shotgun pixel and look left side. In-Game asset. 2d. High contrast. No shadows
submachine gun look left. In-Game asset. 2d. High contrast. No shadows
mp5 gun pixel. In-Game asset. 2d. High contrast. No shadows
Minigun bullet pixel. In-Game asset. 2d. High contrast. No shadows
Eliptic neon laser bullet. In-Game asset. 2d. High contrast. No shadows. Pixel
slime but have metalic helmet. In-Game asset. 2d. High contrast. No shadows
a slime boss enemy very strict. In-Game asset. 2d. High contrast. No shadows
create mirror view a bit smaller
add a dragon baby on top of gun
a goblin slime which have backpack fully coins. In-Game asset. 2d. High contrast. No shadows
Disappear smoke pixel. In-Game asset. 2d. High contrast. No shadows
Coin pile pixel. In-Game asset. 2d. High contrast. No shadows
fire left to right pixel. In-Game asset. 2d. High contrast. No shadows
Slime enemy healer. In-Game asset. 2d. High contrast. No shadows
Healt restore pixel. In-Game asset. 2d. High contrast. No shadows
Ammo +1 upgrade. In-Game asset. 2d. High contrast. No shadows
Type SLOW bottom of the amblem
Fire ball pixel
boss slime but like fire and dangereous. In-Game asset. 2d. High contrast. No shadows
Add body of this slime