/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var Enemy = Container.expand(function () { var self = Container.call(this); var enemyGraphics = self.attachAsset('titan', { anchorX: 0.5, anchorY: 0.5 }); self.maxHealth = 50; self.health = self.maxHealth; self.goldReward = 20; self.isBoss = false; self.waveNumber = 1; // Health bar elements - will be created when enemy is spawned self.healthBarBg = null; self.healthBarFill = null; self.healthText = null; self.createHealthBar = function () { // Health bar background - positioned at top of screen self.healthBarBg = LK.getAsset('upgradeButton', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.8, scaleY: 0.7 }); self.healthBarBg.tint = 0x333333; self.healthBarBg.x = 1024; self.healthBarBg.y = 200; game.addChild(self.healthBarBg); // Health bar fill - positioned at top of screen self.healthBarFill = LK.getAsset('upgradeButton', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.8, scaleY: 0.7 }); self.healthBarFill.tint = 0x27ae60; self.healthBarFill.x = 1024; self.healthBarFill.y = 200; game.addChild(self.healthBarFill); // Health text inside health bar - positioned at top of screen self.healthText = new Text2(formatNumber(self.health) + '/' + formatNumber(self.maxHealth), { size: 32, fill: 0xFFFFFF }); self.healthText.anchor.set(0.5, 0.5); self.healthText.x = 1024; self.healthText.y = 200; game.addChild(self.healthText); }; self.setWaveColor = function (waveNum) { self.waveNumber = waveNum; var colors = [0xffffff, 0xff6b6b, 0x4ecdc4, 0x45b7d1, 0x96ceb4, 0xffeaa7, 0xdda0dd, 0xff7675, 0x74b9ff, 0x00b894]; var colorIndex = (waveNum - 1) % colors.length; enemyGraphics.tint = colors[colorIndex]; }; self.updateHealthBar = function () { var healthPercent = self.health / self.maxHealth; self.healthBarFill.scaleX = 1.8 * healthPercent; if (healthPercent > 0.6) { self.healthBarFill.tint = 0x27ae60; // Green } else if (healthPercent > 0.3) { self.healthBarFill.tint = 0xf39c12; // Orange } else { self.healthBarFill.tint = 0xe74c3c; // Red } // Update health text if (self.healthText) { self.healthText.setText(formatNumber(Math.max(0, self.health)) + '/' + formatNumber(self.maxHealth)); } }; self.takeDamage = function (damage) { var wasAtFullHealth = self.health === self.maxHealth; self.health -= damage; self.updateHealthBar(); // Get current wave color for restore var colors = [0xffffff, 0xff6b6b, 0x4ecdc4, 0x45b7d1, 0x96ceb4, 0xffeaa7, 0xdda0dd, 0xff7675, 0x74b9ff, 0x00b894]; var colorIndex = (self.waveNumber - 1) % colors.length; var originalColor = colors[colorIndex]; // Store original position and scale for animation reset var originalX = enemyGraphics.x; var originalY = enemyGraphics.y; var originalScaleX = enemyGraphics.scaleX; var originalScaleY = enemyGraphics.scaleY; // Enhanced damage animation with scaling and shaking effect tween(enemyGraphics, { tint: 0xff0000, scaleX: originalScaleX * 1.2, scaleY: originalScaleY * 1.2, x: originalX + (Math.random() - 0.5) * 20 }, { duration: 80, easing: tween.easeOut, onFinish: function onFinish() { tween(enemyGraphics, { tint: originalColor, scaleX: originalScaleX, scaleY: originalScaleY, x: originalX, y: originalY }, { duration: 120, easing: tween.easeInOut }); } }); // Create damage number popup var damageText = new Text2('-' + formatNumber(damage), { size: 60, fill: 0xFF0000 }); damageText.anchor.set(0.5, 0.5); damageText.x = self.x + (Math.random() - 0.5) * 80; damageText.y = self.y - 50; damageText.alpha = 1; game.addChild(damageText); // Animate damage text floating up and fading tween(damageText, { y: damageText.y - 120, alpha: 0, scaleX: 0.7, scaleY: 0.7 }, { duration: 800, easing: tween.easeOut, onFinish: function onFinish() { damageText.destroy(); } }); if (self.health <= 0) { // Check if this was a one-shot kill (enemy was at full health before this damage) if (wasAtFullHealth) { self.showHeadshotEffect(); } self.die(); } }; self.showHeadshotEffect = function () { // Play headshot sound effect if (storage.soundEnabled !== false) { LK.getSound('headshot').play(); } // Create headshot text var headshotText = new Text2('HEADSHOT!', { size: 80, fill: 0xFFD700 }); headshotText.anchor.set(0.5, 0.5); headshotText.x = self.x; headshotText.y = self.y - 100; headshotText.alpha = 1; game.addChild(headshotText); // Create pulsing scale effect tween(headshotText, { scaleX: 1.5, scaleY: 1.5 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { tween(headshotText, { scaleX: 1, scaleY: 1, y: headshotText.y - 80, alpha: 0 }, { duration: 800, easing: tween.easeIn, onFinish: function onFinish() { headshotText.destroy(); } }); } }); // Create explosion effect with scaling circle var explosionEffect = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.1, scaleY: 0.1 }); explosionEffect.x = self.x; explosionEffect.y = self.y; explosionEffect.tint = 0xFFD700; explosionEffect.alpha = 0.8; game.addChild(explosionEffect); // Animate explosion expanding and fading tween(explosionEffect, { scaleX: 3, scaleY: 3, alpha: 0 }, { duration: 500, easing: tween.easeOut, onFinish: function onFinish() { explosionEffect.destroy(); } }); }; self.die = function () { gold += self.goldReward * 2; // Increase gold reward by 2x var crystalReward = self.isBoss ? 10 : 3; // Increase crystal reward when wave 100 is passed if (wave >= 100) { crystalReward = Math.floor(crystalReward * 2.5); // 2.5x crystal multiplier for wave 100+ } crystals += crystalReward; updateGoldDisplay(); updateCrystalsDisplay(); if (storage.soundEnabled !== false) { LK.getSound('enemyDeath').play(); } // Destroy health bar elements if (self.healthBarBg && self.healthBarBg.parent) { self.healthBarBg.destroy(); } if (self.healthBarFill && self.healthBarFill.parent) { self.healthBarFill.destroy(); } if (self.healthText && self.healthText.parent) { self.healthText.destroy(); } // Death animation tween(self, { scaleX: 0, scaleY: 0, alpha: 0 }, { duration: 300, onFinish: function onFinish() { var index = enemies.indexOf(self); if (index > -1) { enemies.splice(index, 1); } self.destroy(); spawnNextEnemy(); } }); }; return self; }); var Boss = Enemy.expand(function () { var self = Enemy.call(this); // Replace graphics with boss asset self.removeChildren(); var bossGraphics = self.attachAsset('boss', { anchorX: 0.5, anchorY: 0.5 }); self.maxHealth = 5000; self.health = self.maxHealth; self.goldReward = 500; self.isBoss = true; // Override createHealthBar for boss with larger scale self.createHealthBar = function () { // Health bar background - positioned at top of screen self.healthBarBg = LK.getAsset('upgradeButton', { anchorX: 0.5, anchorY: 0.5, scaleX: 2.2, scaleY: 0.8 }); self.healthBarBg.tint = 0x333333; self.healthBarBg.x = 1024; self.healthBarBg.y = 200; game.addChild(self.healthBarBg); self.healthBarFill = LK.getAsset('upgradeButton', { anchorX: 0.5, anchorY: 0.5, scaleX: 2.2, scaleY: 0.8 }); self.healthBarFill.tint = 0x8e44ad; self.healthBarFill.x = 1024; self.healthBarFill.y = 200; game.addChild(self.healthBarFill); // Health text inside boss health bar - positioned at top of screen self.healthText = new Text2(formatNumber(self.health) + '/' + formatNumber(self.maxHealth), { size: 36, fill: 0xFFFFFF }); self.healthText.anchor.set(0.5, 0.5); self.healthText.x = 1024; self.healthText.y = 200; game.addChild(self.healthText); }; // Override updateHealthBar for boss with larger scale self.updateHealthBar = function () { var healthPercent = self.health / self.maxHealth; self.healthBarFill.scaleX = 2.2 * healthPercent; if (healthPercent > 0.6) { self.healthBarFill.tint = 0x8e44ad; // Purple for boss } else if (healthPercent > 0.3) { self.healthBarFill.tint = 0x9b59b6; // Lighter purple } else { self.healthBarFill.tint = 0xe74c3c; // Red } // Update health text if (self.healthText) { self.healthText.setText(formatNumber(Math.max(0, self.health)) + '/' + formatNumber(self.maxHealth)); } }; var originalSetWaveColor = self.setWaveColor; self.setWaveColor = function (waveNum) { self.waveNumber = waveNum; // Bosses always stay purple but get darker with higher waves var darkness = Math.min(waveNum * 0.1, 0.7); var baseColor = 0x8e44ad; var r = baseColor >> 16 & 0xFF; var g = baseColor >> 8 & 0xFF; var b = baseColor & 0xFF; r = Math.floor(r * (1 - darkness)); g = Math.floor(g * (1 - darkness)); b = Math.floor(b * (1 - darkness)); bossGraphics.tint = r << 16 | g << 8 | b; }; // Override takeDamage for boss with enhanced effects self.takeDamage = function (damage) { var wasAtFullHealth = self.health === self.maxHealth; self.health -= damage; self.updateHealthBar(); // Store original position and scale for animation reset var originalX = bossGraphics.x; var originalY = bossGraphics.y; var originalScaleX = bossGraphics.scaleX; var originalScaleY = bossGraphics.scaleY; // More dramatic boss damage animation tween(bossGraphics, { tint: 0xff0000, scaleX: originalScaleX * 1.15, scaleY: originalScaleY * 1.15, x: originalX + (Math.random() - 0.5) * 30, y: originalY + (Math.random() - 0.5) * 15 }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { tween(bossGraphics, { tint: 0x8e44ad, scaleX: originalScaleX, scaleY: originalScaleY, x: originalX, y: originalY }, { duration: 150, easing: tween.easeInOut }); } }); // Create larger damage number for boss var damageText = new Text2('-' + formatNumber(damage), { size: 80, fill: 0xFF4444 }); damageText.anchor.set(0.5, 0.5); damageText.x = self.x + (Math.random() - 0.5) * 100; damageText.y = self.y - 80; damageText.alpha = 1; game.addChild(damageText); // Animate boss damage text with more dramatic effect tween(damageText, { y: damageText.y - 150, alpha: 0, scaleX: 1.2, scaleY: 1.2 }, { duration: 1000, easing: tween.easeOut, onFinish: function onFinish() { damageText.destroy(); } }); if (self.health <= 0) { // Check if this was a one-shot kill (enemy was at full health before this damage) if (wasAtFullHealth) { self.showHeadshotEffect(); } self.die(); } }; // Override showHeadshotEffect for boss with more dramatic effect self.showHeadshotEffect = function () { // Play headshot sound effect for boss if (storage.soundEnabled !== false) { LK.getSound('headshot').play(); } // Create headshot text for boss (bigger and more dramatic) var headshotText = new Text2('BOSS HEADSHOT!', { size: 100, fill: 0xFF0000 }); headshotText.anchor.set(0.5, 0.5); headshotText.x = self.x; headshotText.y = self.y - 150; headshotText.alpha = 1; game.addChild(headshotText); // Create pulsing scale effect tween(headshotText, { scaleX: 2, scaleY: 2 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { tween(headshotText, { scaleX: 1, scaleY: 1, y: headshotText.y - 100, alpha: 0 }, { duration: 1000, easing: tween.easeIn, onFinish: function onFinish() { headshotText.destroy(); } }); } }); // Create larger explosion effect for boss var explosionEffect = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.1, scaleY: 0.1 }); explosionEffect.x = self.x; explosionEffect.y = self.y; explosionEffect.tint = 0xFF0000; explosionEffect.alpha = 1; game.addChild(explosionEffect); // Animate boss explosion expanding and fading tween(explosionEffect, { scaleX: 5, scaleY: 5, alpha: 0 }, { duration: 700, easing: tween.easeOut, onFinish: function onFinish() { explosionEffect.destroy(); } }); }; return self; }); var Hero = Container.expand(function () { var self = Container.call(this); var heroGraphics = self.attachAsset('hero', { anchorX: 0.5, anchorY: 0.5 }); self.level = 1; self.damage = 5; self.attackSpeed = 1000; // milliseconds between attacks self.lastAttackTime = 0; self.cost = 100; self.type = 'DPS'; // DPS, Support, Tank self.attack = function () { if (currentEnemy && LK.ticks * 16.67 - self.lastAttackTime >= self.attackSpeed / gameSpeed) { // Add hero arm animation when attacking tween(heroGraphics, { rotation: 0.2 }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { tween(heroGraphics, { rotation: 0 }, { duration: 100, easing: tween.easeIn }); } }); var projectile = new HeroProjectile(); projectile.x = self.x; projectile.y = self.y; projectile.targetX = currentEnemy.x; projectile.targetY = currentEnemy.y; projectile.damage = self.damage; projectiles.push(projectile); game.addChild(projectile); if (storage.soundEnabled !== false) { LK.getSound('attack').play(); } self.lastAttackTime = LK.ticks * 16.67; } }; self.upgrade = function () { var upgradeCost = Math.floor(self.cost * Math.pow(1.15, self.level - 1)); if (gold >= upgradeCost) { gold -= upgradeCost; self.level++; self.damage = Math.floor(self.damage * 1.1); self.cost = upgradeCost; storage.heroLevel = self.level; updateGoldDisplay(); } }; self.update = function () { self.attack(); }; return self; }); var HeroProjectile = Container.expand(function () { var self = Container.call(this); var projectileGraphics = self.attachAsset('heroProjectile', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 8; self.damage = 5; self.targetX = 0; self.targetY = 0; self.update = function () { var dx = self.targetX - self.x; var dy = self.targetY - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 10) { // Hit target if (currentEnemy) { currentEnemy.takeDamage(self.damage); } var index = projectiles.indexOf(self); if (index > -1) { projectiles.splice(index, 1); } self.destroy(); } else { // Move towards target self.x += dx / distance * self.speed * gameSpeed; self.y += dy / distance * self.speed * gameSpeed; } }; return self; }); var SettingsPanel = Container.expand(function () { var self = Container.call(this); // Semi-transparent overlay var overlay = LK.getAsset('settingsPanel', { anchorX: 0.5, anchorY: 0.5, scaleX: 4, scaleY: 4 }); overlay.tint = 0x000000; overlay.alpha = 0.8; overlay.x = 1024; overlay.y = 1366; self.addChild(overlay); // Settings panel background var panelBg = self.attachAsset('settingsPanel', { anchorX: 0.5, anchorY: 0.5 }); panelBg.x = 1024; panelBg.y = 1366; // Title var titleText = new Text2('AYARLAR', { size: 60, fill: 0xFFFFFF }); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 1066; self.addChild(titleText); // Music toggle var musicToggle = LK.getAsset('toggleButton', { anchorX: 0.5, anchorY: 0.5 }); musicToggle.x = 1174; musicToggle.y = 1200; musicToggle.tint = storage.musicEnabled !== false ? 0x27ae60 : 0xe74c3c; self.addChild(musicToggle); var musicLabel = new Text2('Müzik:', { size: 40, fill: 0xFFFFFF }); musicLabel.anchor.set(0, 0.5); musicLabel.x = 774; musicLabel.y = 1200; self.addChild(musicLabel); var musicText = new Text2(storage.musicEnabled !== false ? 'AÇIK' : 'KAPALI', { size: 30, fill: 0xFFFFFF }); musicText.anchor.set(0.5, 0.5); musicText.x = 1174; musicText.y = 1200; self.addChild(musicText); musicToggle.down = function () { storage.musicEnabled = !storage.musicEnabled; musicToggle.tint = storage.musicEnabled ? 0x27ae60 : 0xe74c3c; musicText.setText(storage.musicEnabled ? 'AÇIK' : 'KAPALI'); if (storage.musicEnabled) { LK.playMusic('battleMusic'); } else { LK.stopMusic(); } }; // Sound effects toggle var soundToggle = LK.getAsset('toggleButton', { anchorX: 0.5, anchorY: 0.5 }); soundToggle.x = 1174; soundToggle.y = 1300; soundToggle.tint = storage.soundEnabled !== false ? 0x27ae60 : 0xe74c3c; self.addChild(soundToggle); var soundLabel = new Text2('Efektler:', { size: 40, fill: 0xFFFFFF }); soundLabel.anchor.set(0, 0.5); soundLabel.x = 774; soundLabel.y = 1300; self.addChild(soundLabel); var soundText = new Text2(storage.soundEnabled !== false ? 'AÇIK' : 'KAPALI', { size: 30, fill: 0xFFFFFF }); soundText.anchor.set(0.5, 0.5); soundText.x = 1174; soundText.y = 1300; self.addChild(soundText); soundToggle.down = function () { storage.soundEnabled = !storage.soundEnabled; soundToggle.tint = storage.soundEnabled ? 0x27ae60 : 0xe74c3c; soundText.setText(storage.soundEnabled ? 'AÇIK' : 'KAPALI'); }; // Language toggle var langToggle = LK.getAsset('toggleButton', { anchorX: 0.5, anchorY: 0.5 }); langToggle.x = 1174; langToggle.y = 1400; langToggle.tint = 0x3498db; self.addChild(langToggle); var langLabel = new Text2('Dil:', { size: 40, fill: 0xFFFFFF }); langLabel.anchor.set(0, 0.5); langLabel.x = 774; langLabel.y = 1400; self.addChild(langLabel); var langText = new Text2(storage.language || 'TR', { size: 30, fill: 0xFFFFFF }); langText.anchor.set(0.5, 0.5); langText.x = 1174; langText.y = 1400; self.addChild(langText); langToggle.down = function () { storage.language = storage.language === 'EN' ? 'TR' : 'EN'; gameLanguage = storage.language; langText.setText(storage.language); self.updateLanguage(); updateAllLanguageTexts(); }; // Reset game button var resetBtn = LK.getAsset('settingsButton', { anchorX: 0.5, anchorY: 0.5 }); resetBtn.x = 1024; resetBtn.y = 1500; resetBtn.tint = 0xe74c3c; self.addChild(resetBtn); var resetText = new Text2('OYUNU SIFIRLA', { size: 36, fill: 0xFFFFFF }); resetText.anchor.set(0.5, 0.5); resetText.x = 1024; resetText.y = 1500; self.addChild(resetText); resetBtn.down = function () { // Reset all game state and upgrades storage.gold = 500; storage.crystals = 10; storage.wave = 1; storage.currentDPS = 0; delete storage.heroLevel; delete storage.prestigeMultiplier; LK.showGameOver(); }; // Close button var closeBtn = LK.getAsset('settingsButton', { anchorX: 0.5, anchorY: 0.5 }); closeBtn.x = 1024; closeBtn.y = 1600; closeBtn.tint = 0x95a5a6; self.addChild(closeBtn); var closeText = new Text2('KAPAT', { size: 36, fill: 0xFFFFFF }); closeText.anchor.set(0.5, 0.5); closeText.x = 1024; closeText.y = 1600; self.addChild(closeText); closeBtn.down = function () { self.hide(); }; self.updateLanguage = function () { var isEn = storage.language === 'EN'; titleText.setText(isEn ? 'SETTINGS' : 'AYARLAR'); musicLabel.setText(isEn ? 'Music:' : 'Müzik:'); soundLabel.setText(isEn ? 'Effects:' : 'Efektler:'); langLabel.setText(isEn ? 'Language:' : 'Dil:'); musicText.setText(storage.musicEnabled !== false ? isEn ? 'ON' : 'AÇIK' : isEn ? 'OFF' : 'KAPALI'); soundText.setText(storage.soundEnabled !== false ? isEn ? 'ON' : 'AÇIK' : isEn ? 'OFF' : 'KAPALI'); resetText.setText(isEn ? 'RESET GAME' : 'OYUNU SIFIRLA'); closeText.setText(isEn ? 'CLOSE' : 'KAPAT'); }; self.show = function () { self.alpha = 1; self.visible = true; game.isPaused = true; // Bring settings panel to front to ensure it's on top if (self.parent) { self.parent.setChildIndex(self, self.parent.children.length - 1); } // Also ensure overlay is on top if (overlay.parent) { overlay.parent.setChildIndex(overlay, overlay.parent.children.length - 1); } // And ensure panel background is on top if (panelBg.parent) { panelBg.parent.setChildIndex(panelBg, panelBg.parent.children.length - 1); } // Bring all text and buttons to front to ensure they're above the panel if (titleText.parent) { titleText.parent.setChildIndex(titleText, titleText.parent.children.length - 1); } if (musicToggle.parent) { musicToggle.parent.setChildIndex(musicToggle, musicToggle.parent.children.length - 1); } if (musicLabel.parent) { musicLabel.parent.setChildIndex(musicLabel, musicLabel.parent.children.length - 1); } if (musicText.parent) { musicText.parent.setChildIndex(musicText, musicText.parent.children.length - 1); } if (soundToggle.parent) { soundToggle.parent.setChildIndex(soundToggle, soundToggle.parent.children.length - 1); } if (soundLabel.parent) { soundLabel.parent.setChildIndex(soundLabel, soundLabel.parent.children.length - 1); } if (soundText.parent) { soundText.parent.setChildIndex(soundText, soundText.parent.children.length - 1); } if (langToggle.parent) { langToggle.parent.setChildIndex(langToggle, langToggle.parent.children.length - 1); } if (langLabel.parent) { langLabel.parent.setChildIndex(langLabel, langLabel.parent.children.length - 1); } if (langText.parent) { langText.parent.setChildIndex(langText, langText.parent.children.length - 1); } if (resetBtn.parent) { resetBtn.parent.setChildIndex(resetBtn, resetBtn.parent.children.length - 1); } if (resetText.parent) { resetText.parent.setChildIndex(resetText, resetText.parent.children.length - 1); } if (closeBtn.parent) { closeBtn.parent.setChildIndex(closeBtn, closeBtn.parent.children.length - 1); } if (closeText.parent) { closeText.parent.setChildIndex(closeText, closeText.parent.children.length - 1); } }; self.hide = function () { self.alpha = 0; self.visible = false; game.isPaused = false; }; // Start hidden self.hide(); return self; }); var TutorialPanel = Container.expand(function () { var self = Container.call(this); // Semi-transparent overlay var overlay = LK.getAsset('settingsPanel', { anchorX: 0.5, anchorY: 0.5, scaleX: 4, scaleY: 4 }); overlay.tint = 0x000000; overlay.alpha = 0.9; overlay.x = 1024; overlay.y = 1366; self.addChild(overlay); // Tutorial panel background var panelBg = self.attachAsset('settingsPanel', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.2, scaleY: 1.3 }); panelBg.x = 1024; panelBg.y = 1366; // Title var titleText = new Text2('OYUNU ÖĞRENİN', { size: 60, fill: 0xFFFFFF }); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 1000; self.addChild(titleText); // Tutorial content var tutorialText = new Text2('• Ekrana dokunarak altın kazanın\n• Altınla kahramanınızı güçlendirin\n• Dalgaları geçip kristal toplayın\n• 1000 kristalle prestij yapın\n• Bossları yenip ilerleyin!', { size: 36, fill: 0xFFFFFF }); tutorialText.anchor.set(0.5, 0.5); tutorialText.x = 1024; tutorialText.y = 1300; self.addChild(tutorialText); // Gold tap hint var tapHintText = new Text2('💰 EKRANA DOKUNUN = ALTIN 💰', { size: 40, fill: 0xFFD700 }); tapHintText.anchor.set(0.5, 0.5); tapHintText.x = 1024; tapHintText.y = 1500; self.addChild(tapHintText); // Close button (X) var closeBtn = LK.getAsset('settingsIcon', { anchorX: 0.5, anchorY: 0.5 }); closeBtn.x = 1300; closeBtn.y = 900; closeBtn.tint = 0xe74c3c; self.addChild(closeBtn); var closeText = new Text2('✕', { size: 50, fill: 0xFFFFFF }); closeText.anchor.set(0.5, 0.5); closeBtn.addChild(closeText); closeBtn.down = function () { self.hide(); }; self.show = function () { self.alpha = 1; self.visible = true; game.isPaused = true; }; self.updateLanguage = function () { titleText.setText(getText('learnGame')); tutorialText.setText(getText('tutorialText')); tapHintText.setText(getText('tapHint')); }; self.hide = function () { self.alpha = 0; self.visible = false; game.isPaused = false; // Mark tutorial as seen storage.tutorialSeen = true; }; // Start visible self.alpha = 1; self.visible = true; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x2c3e50 }); /**** * Game Code ****/ // Add background image var backgroundImage = LK.getAsset('background', { anchorX: 0, anchorY: 0 }); backgroundImage.x = 0; backgroundImage.y = 0; game.addChild(backgroundImage); // Reset game state - clear all storage storage.gold = 500; storage.crystals = 10; storage.wave = 1; storage.currentDPS = 0; storage.prestigeMultiplier = 1; delete storage.heroLevel; delete storage.autoUpgradeEnabled; delete storage.autoClickEnabled; delete storage.gameSpeed; delete storage.tutorialSeen; // Game state variables var gold = 500; var crystals = 10; var wave = 1; var currentDPS = 0; var prestigeMultiplier = 1; var heroes = []; var enemies = []; var projectiles = []; var currentEnemy = null; // UI elements var goldText = new Text2('Gold: ' + gold, { size: 40, fill: 0xFFD700 }); goldText.anchor.set(0, 0); goldText.x = 120; goldText.y = 50; // Add to game but will be moved to top layer in update function game.addChild(goldText); var crystalsText = new Text2('Crystals: ' + crystals, { size: 40, fill: 0x9B59B6 }); crystalsText.anchor.set(0, 0); crystalsText.x = 120; crystalsText.y = 100; // Add to game but will be moved to top layer in update function game.addChild(crystalsText); var waveText = new Text2('Wave: ' + wave, { size: 50, fill: 0xFFFFFF }); waveText.anchor.set(0.5, 0); waveText.x = 1024; waveText.y = 50; // Add to game but will be moved to top layer in update function game.addChild(waveText); var dpsText = new Text2('DPS: ' + currentDPS, { size: 40, fill: 0xE74C3C }); dpsText.anchor.set(1, 0); dpsText.x = 1928; dpsText.y = 50; // Add to game but will be moved to top layer in update function game.addChild(dpsText); var prestigePointsText = new Text2('Prestige: ' + Math.floor(prestigeMultiplier * 100 - 100) + ' (' + prestigeMultiplier.toFixed(1) + 'x)', { size: 35, fill: 0x9B59B6 }); prestigePointsText.anchor.set(1, 0); prestigePointsText.x = 1928; prestigePointsText.y = 100; // Add to game but will be moved to top layer in update function game.addChild(prestigePointsText); // Damage upgrade button var upgradeBtn = LK.getAsset('upgradeButton', { anchorX: 0.5, anchorY: 0.5 }); upgradeBtn.x = -260; upgradeBtn.y = -40; LK.gui.bottom.addChild(upgradeBtn); var upgradeBtnText = new Text2('Upgrade Damage\n100 Gold', { size: 22, fill: 0xFFFFFF }); upgradeBtnText.anchor.set(0.5, 0.5); upgradeBtnText.x = 0; upgradeBtnText.y = 0; upgradeBtn.addChild(upgradeBtnText); upgradeBtn.down = function () { if (heroes.length > 0) { var baseCost = 100; // Use fixed base cost var upgradeCost = Math.floor(baseCost * Math.pow(1.15, heroes[0].level - 1)); if (gold >= upgradeCost) { gold -= upgradeCost; heroes[0].level++; heroes[0].damage = Math.floor(heroes[0].damage * 1.2); // Increase damage by 20% per upgrade storage.heroLevel = heroes[0].level; updateGoldDisplay(); updateUpgradeButton(); } } }; // Auto upgrade button var autoUpgradeBtn = LK.getAsset('upgradeButton', { anchorX: 0.5, anchorY: 0.5 }); autoUpgradeBtn.x = -60; autoUpgradeBtn.y = -40; LK.gui.bottom.addChild(autoUpgradeBtn); var autoUpgradeBtnText = new Text2('Auto\nOFF', { size: 22, fill: 0xFFFFFF }); autoUpgradeBtnText.anchor.set(0.5, 0.5); autoUpgradeBtnText.x = 0; autoUpgradeBtnText.y = 0; autoUpgradeBtn.addChild(autoUpgradeBtnText); // Auto upgrade state var autoUpgradeEnabled = false; var autoUpgradeLastCheck = 0; // Auto click button var autoClickBtn = LK.getAsset('upgradeButton', { anchorX: 0.5, anchorY: 0.5 }); autoClickBtn.x = 50; autoClickBtn.y = 0; LK.gui.left.addChild(autoClickBtn); var autoClickBtnText = new Text2('Auto\nClick\nOFF', { size: 18, fill: 0xFFFFFF }); autoClickBtnText.anchor.set(0.5, 0.5); autoClickBtnText.x = 0; autoClickBtnText.y = 0; autoClickBtn.addChild(autoClickBtnText); // Auto click state var autoClickEnabled = false; var autoClickLastTime = 0; var autoClickInterval = 1000; // Click every 1000ms (1 time per second) // Update auto upgrade button display function updateAutoUpgradeButton() { if (autoUpgradeEnabled) { autoUpgradeBtn.tint = 0x27ae60; // Green when enabled autoUpgradeBtnText.setText('Auto\nON'); } else { autoUpgradeBtn.tint = 0xe74c3c; // Red when disabled autoUpgradeBtnText.setText('Auto\nOFF'); } } // Update auto click button display function updateAutoClickButton() { if (autoClickEnabled) { autoClickBtn.tint = 0x27ae60; // Green when enabled autoClickBtnText.setText('Auto\nClick\nON'); } else { autoClickBtn.tint = 0xe74c3c; // Red when disabled autoClickBtnText.setText('Auto\nClick\nOFF'); } } // Initialize auto upgrade button state updateAutoUpgradeButton(); autoUpgradeBtn.down = function () { autoUpgradeEnabled = !autoUpgradeEnabled; storage.autoUpgradeEnabled = autoUpgradeEnabled; updateAutoUpgradeButton(); }; // Initialize auto click button state updateAutoClickButton(); autoClickBtn.down = function () { autoClickEnabled = !autoClickEnabled; storage.autoClickEnabled = autoClickEnabled; updateAutoClickButton(); }; // Auto upgrade function function performAutoUpgrade() { if (!autoUpgradeEnabled || heroes.length === 0) { return; } var baseCost = 100; var upgradeCost = Math.floor(baseCost * Math.pow(1.15, heroes[0].level - 1)); if (gold >= upgradeCost) { gold -= upgradeCost; heroes[0].level++; heroes[0].damage = Math.floor(heroes[0].damage * 1.2); storage.heroLevel = heroes[0].level; updateGoldDisplay(); updateUpgradeButton(); } } // Summon button removed - hero çağır butonunu kaldır // Prestige button var prestigeBtn = LK.getAsset('summonButton', { anchorX: 0.5, anchorY: 0.5 }); prestigeBtn.x = 120; prestigeBtn.y = -40; LK.gui.bottom.addChild(prestigeBtn); var prestigeBtnText = new Text2(getText('Prestige') + '\n' + formatNumber(500) + ' ' + getText('Crystals'), { size: 24, fill: 0xFFFFFF }); prestigeBtnText.anchor.set(0.5, 0.5); prestigeBtnText.x = 0; prestigeBtnText.y = 0; prestigeBtn.addChild(prestigeBtnText); prestigeBtn.down = function () { if (crystals >= 500) { crystals -= 500; doPrestige(); updateCrystalsDisplay(); } }; // Game speed control var gameSpeed = 1; var gameSpeedMultipliers = [1, 2]; var gameSpeedButton = LK.getAsset('toggleButton', { anchorX: 0.5, anchorY: 0.5 }); gameSpeedButton.x = -50; gameSpeedButton.y = -120; LK.gui.bottomRight.addChild(gameSpeedButton); var gameSpeedText = new Text2(gameSpeed + 'x', { size: 30, fill: 0xFFFFFF }); gameSpeedText.anchor.set(0.5, 0.5); gameSpeedText.x = 0; gameSpeedText.y = 0; gameSpeedButton.addChild(gameSpeedText); gameSpeedButton.down = function () { var currentIndex = gameSpeedMultipliers.indexOf(gameSpeed); var nextIndex = (currentIndex + 1) % gameSpeedMultipliers.length; gameSpeed = gameSpeedMultipliers[nextIndex]; storage.gameSpeed = gameSpeed; gameSpeedText.setText(gameSpeed + 'x'); }; // Settings icon in bottom right var settingsIcon = LK.getAsset('settingsIcon', { anchorX: 0.5, anchorY: 0.5 }); settingsIcon.x = -50; settingsIcon.y = -50; LK.gui.bottomRight.addChild(settingsIcon); var settingsText = new Text2('⚙', { size: 50, fill: 0xFFFFFF }); settingsText.anchor.set(0.5, 0.5); settingsText.x = 0; settingsText.y = 0; settingsIcon.addChild(settingsText); // Settings panel var settingsPanel = new SettingsPanel(); game.addChild(settingsPanel); settingsIcon.down = function () { settingsPanel.show(); }; // Tutorial panel - show only once for new players var tutorialPanel = new TutorialPanel(); game.addChild(tutorialPanel); // Show tutorial for fresh start tutorialPanel.show(); game.isPaused = true; // Language system var gameLanguage = storage.language || 'TR'; var languageTexts = { TR: { gold: 'Altın', crystals: 'Kristal', wave: 'Dalga', dps: 'DPS', upgradeDamage: 'Hasarı Yükselt', prestige: 'Prestij', settings: 'AYARLAR', music: 'Müzik:', effects: 'Efektler:', language: 'Dil:', on: 'AÇIK', off: 'KAPALI', resetGame: 'OYUNU SIFIRLA', close: 'KAPAT', learnGame: 'OYUNU ÖĞRENİN', tutorialText: '• Ekrana dokunarak altın kazanın\n• Altınla kahramanınızı güçlendirin\n• Dalgaları geçip kristal toplayın\n• 1000 kristalle prestij yapın\n• Bossları yenip ilerleyin!', tapHint: '🏆 EKRANA DOKUNUN = ALTIN', gold_unit: 'Altın', crystals_unit: 'Kristal' }, EN: { gold: 'Gold', crystals: 'Crystals', wave: 'Wave', dps: 'DPS', upgradeDamage: 'Upgrade Damage', prestige: 'Prestige', settings: 'SETTINGS', music: 'Music:', effects: 'Effects:', language: 'Language:', on: 'ON', off: 'OFF', resetGame: 'RESET GAME', close: 'CLOSE', learnGame: 'LEARN THE GAME', tutorialText: '• Tap screen to earn gold\n• Use gold to upgrade your hero\n• Beat waves to collect crystals\n• Prestige with 1000 crystals\n• Defeat bosses to progress!', tapHint: '🏆 TAP SCREEN = GOLD', gold_unit: 'Gold', crystals_unit: 'Crystals' } }; function getText(key) { // Ensure languageTexts object exists if (!languageTexts) { return key; } // Ensure gameLanguage is valid, default to 'TR' if not var lang = gameLanguage && languageTexts[gameLanguage] ? gameLanguage : 'TR'; // Safely access language texts with fallbacks if (languageTexts[lang] && languageTexts[lang][key]) { return languageTexts[lang][key]; } if (languageTexts.TR && languageTexts.TR[key]) { return languageTexts.TR[key]; } return key; // Return the key itself as fallback } // Number formatting function for global abbreviations function formatNumber(num) { if (num < 1000) { return num.toString(); } if (num < 1000000) { return (num / 1000).toFixed(1) + 'K'; } if (num < 1000000000) { return (num / 1000000).toFixed(1) + 'M'; } if (num < 1000000000000) { return (num / 1000000000).toFixed(1) + 'B'; } if (num < 1000000000000000) { return (num / 1000000000000).toFixed(1) + 'T'; } if (num < 1000000000000000000) { return (num / 1000000000000000).toFixed(1) + 'Q'; } return (num / 1000000000000000000).toFixed(1) + 'Qi'; } // Game functions function updateGoldDisplay() { goldText.setText(getText('gold') + ': ' + formatNumber(gold)); storage.gold = gold; } function updateCrystalsDisplay() { crystalsText.setText(getText('crystals') + ': ' + formatNumber(crystals)); storage.crystals = crystals; } function updateWaveDisplay() { waveText.setText(getText('wave') + ': ' + formatNumber(wave)); storage.wave = wave; } function updateDPSDisplay() { var totalDPS = 0; for (var i = 0; i < heroes.length; i++) { totalDPS += Math.floor(heroes[i].damage * 1000 / heroes[i].attackSpeed); } currentDPS = totalDPS; storage.currentDPS = currentDPS; dpsText.setText(getText('dps') + ': ' + formatNumber(totalDPS)); } function updatePrestigePointsDisplay() { var points = Math.floor(prestigeMultiplier * 100 - 100); prestigePointsText.setText('Prestij: ' + points + ' (' + prestigeMultiplier.toFixed(1) + 'x)'); } function updateUpgradeButton() { if (heroes.length > 0) { var baseCost = 100; // Use fixed base cost instead of hero.cost var cost = Math.floor(baseCost * Math.pow(1.15, heroes[0].level)); upgradeBtnText.setText(getText('upgradeDamage') + '\n' + formatNumber(cost) + ' ' + getText('gold_unit')); } } function updateAllLanguageTexts() { // Update main UI displays updateGoldDisplay(); updateCrystalsDisplay(); updateWaveDisplay(); updateDPSDisplay(); updatePrestigePointsDisplay(); updateUpgradeButton(); // Update prestige button prestigeBtnText.setText(getText('prestige') + '\n' + formatNumber(500) + ' ' + getText('crystals_unit')); // Update settings panel if it exists if (settingsPanel && settingsPanel.updateLanguage) { settingsPanel.updateLanguage(); } // Update tutorial panel if it exists if (tutorialPanel && tutorialPanel.updateLanguage) { tutorialPanel.updateLanguage(); } } function summonHero() { var hero = new Hero(); hero.x = 300 + heroes.length * 100; hero.y = 1800; // Apply stored upgrade levels if (storage.heroLevel) { hero.level = storage.heroLevel; hero.damage = Math.floor(10 * Math.pow(1.1, hero.level - 1) * prestigeMultiplier); } // Apply prestige multiplier to new heroes hero.damage = Math.floor(hero.damage * prestigeMultiplier); heroes.push(hero); game.addChild(hero); } function doPrestige() { // Increase prestige multiplier by 1.2x prestigeMultiplier *= 1.2; storage.prestigeMultiplier = prestigeMultiplier; // Reset all game state gold = 500; crystals = 10; wave = 1; currentDPS = 0; // Clear all game objects for (var i = heroes.length - 1; i >= 0; i--) { heroes[i].destroy(); } heroes = []; for (var i = enemies.length - 1; i >= 0; i--) { enemies[i].destroy(); } enemies = []; currentEnemy = null; for (var i = projectiles.length - 1; i >= 0; i--) { projectiles[i].destroy(); } projectiles = []; // Clear storage upgrades (reset upgrades on prestige) delete storage.heroLevel; // Update storage with reset values storage.gold = gold; storage.crystals = crystals; storage.wave = wave; storage.currentDPS = currentDPS; // Update displays updateGoldDisplay(); updateCrystalsDisplay(); updateWaveDisplay(); updateDPSDisplay(); updatePrestigePointsDisplay(); // Restart the game with prestige bonus summonHero(); spawnEnemy(); } function spawnEnemy() { // Don't spawn if there are already enemies alive if (enemies.length > 0 || currentEnemy) { return; } var enemy; if (wave % 10 === 0) { // Boss wave - only spawn boss enemy = new Boss(); enemy.maxHealth = Math.floor(250 * Math.pow(5.0, Math.floor(wave / 10))); } else { // Regular wave - spawn single titan enemy = new Enemy(); enemy.maxHealth = Math.floor(50 * Math.pow(1.15, wave)); } enemy.health = enemy.maxHealth; enemy.goldReward = Math.floor(enemy.goldReward * Math.pow(1.1, wave)); enemy.setWaveColor(wave); enemy.createHealthBar(); enemy.updateHealthBar(); enemy.x = 1500; enemy.y = 1800; enemies.push(enemy); game.addChild(enemy); currentEnemy = enemy; } function spawnNextEnemy() { // Clear current enemy reference currentEnemy = null; // Always spawn next enemy after a small delay LK.setTimeout(function () { // Check if we should proceed to next wave if (enemies.length === 0) { wave++; updateWaveDisplay(); } spawnEnemy(); }, 1000 / gameSpeed); } // Initialize first hero and enemy summonHero(); spawnEnemy(); // Start background music if (storage.musicEnabled !== false) { LK.playMusic('battleMusic'); } // Click rate limiting variables var clickTimes = []; var maxClicksPerSecond = 10; var maxTotalClicksPerSecond = 20; // Hold state variables var isHolding = false; var holdStartTime = 0; var lastGoldGenTime = 0; var goldPerSecondWhileHolding = 5; // Generate 5 gold per second while holding // Screen tap handler for gold generation game.down = function (x, y, obj) { // Only give gold if game is not paused if (!game.isPaused) { var currentTime = Date.now(); // Clean up old click times (older than 1 second) clickTimes = clickTimes.filter(function (time) { return currentTime - time < 1000; }); // Check if we've exceeded the click limits if (clickTimes.length >= maxTotalClicksPerSecond) { return; // Block the click if we've hit the 20 clicks per second limit } // Check if we've exceeded 10 clicks in the last 100ms (to ensure max 10 clicks per second rate) var recentClicks = clickTimes.filter(function (time) { return currentTime - time < 100; }); if (recentClicks.length >= 1) { return; // Block the click if we've already clicked in the last 100ms } // Record this click time clickTimes.push(currentTime); // Start holding state isHolding = true; holdStartTime = currentTime; lastGoldGenTime = currentTime; var tapGold = Math.floor((2 + wave * 1) * prestigeMultiplier); // Increase tap gold by 1.5x when wave 100 is passed if (wave >= 100) { tapGold = Math.floor(tapGold * 1.5); } gold += tapGold; updateGoldDisplay(); // Create gold icon animation var goldIcon = LK.getAsset('goldIcon', { anchorX: 0.5, anchorY: 0.5 }); goldIcon.x = x; goldIcon.y = y; goldIcon.alpha = 1; game.addChild(goldIcon); // Animate gold icon moving up and fading out tween(goldIcon, { y: y - 100, alpha: 0 }, { duration: 800, easing: tween.easeOut, onFinish: function onFinish() { goldIcon.destroy(); } }); } }; // Screen release handler game.up = function (x, y, obj) { isHolding = false; }; // Main game loop game.update = function () { // Skip update if game is paused if (game.isPaused) { return; } // Check for wave 100 attack speed boost if (wave >= 100) { // Apply 1.25x attack speed boost to all heroes for (var i = 0; i < heroes.length; i++) { if (!heroes[i].speedBoosted) { heroes[i].attackSpeed = Math.floor(heroes[i].attackSpeed / 1.25); heroes[i].speedBoosted = true; } } } // Handle continuous gold generation while holding if (isHolding) { var currentTime = Date.now(); var timeSinceLastGold = currentTime - lastGoldGenTime; // Generate gold every 200ms (5 times per second) if (timeSinceLastGold >= 200) { var holdGold = Math.floor((1 + wave * 0.5) * prestigeMultiplier); gold += holdGold; updateGoldDisplay(); lastGoldGenTime = currentTime; // Create small gold icon animation at random position var goldIcon = LK.getAsset('goldIcon', { anchorX: 0.5, anchorY: 0.5 }); goldIcon.x = 800 + Math.random() * 400; // Random x between 800-1200 goldIcon.y = 1000 + Math.random() * 400; // Random y between 1000-1400 goldIcon.alpha = 0.8; goldIcon.scaleX = 0.7; goldIcon.scaleY = 0.7; game.addChild(goldIcon); // Animate small gold icon tween(goldIcon, { y: goldIcon.y - 50, alpha: 0 }, { duration: 600, easing: tween.easeOut, onFinish: function onFinish() { goldIcon.destroy(); } }); } } // Update displays updateDPSDisplay(); updatePrestigePointsDisplay(); updateUpgradeButton(); // Move UI texts to top layer every frame to ensure they stay on top if (goldText && goldText.parent) { goldText.parent.setChildIndex(goldText, goldText.parent.children.length - 1); } if (crystalsText && crystalsText.parent) { crystalsText.parent.setChildIndex(crystalsText, crystalsText.parent.children.length - 1); } if (waveText && waveText.parent) { waveText.parent.setChildIndex(waveText, waveText.parent.children.length - 1); } if (dpsText && dpsText.parent) { dpsText.parent.setChildIndex(dpsText, dpsText.parent.children.length - 1); } if (prestigePointsText && prestigePointsText.parent) { prestigePointsText.parent.setChildIndex(prestigePointsText, prestigePointsText.parent.children.length - 1); } // Auto upgrade check (every 100ms to avoid lag) if (LK.ticks % 6 === 0) { performAutoUpgrade(); } // Auto click check (every 60 ticks = 1 second) if (autoClickEnabled && LK.ticks % 60 === 0) { var currentTime = Date.now(); if (currentTime - autoClickLastTime >= 1000) { // Give 1 gold per second var tapGold = 1; gold += tapGold; updateGoldDisplay(); autoClickLastTime = currentTime; // Create gold icon animation at random position var goldIcon = LK.getAsset('goldIcon', { anchorX: 0.5, anchorY: 0.5 }); goldIcon.x = 800 + Math.random() * 400; // Random x between 800-1200 goldIcon.y = 1000 + Math.random() * 400; // Random y between 1000-1400 goldIcon.alpha = 0.8; goldIcon.scaleX = 0.7; goldIcon.scaleY = 0.7; game.addChild(goldIcon); // Animate gold icon tween(goldIcon, { y: goldIcon.y - 50, alpha: 0 }, { duration: 600, easing: tween.easeOut, onFinish: function onFinish() { goldIcon.destroy(); } }); } } // Clean up destroyed projectiles for (var i = projectiles.length - 1; i >= 0; i--) { if (!projectiles[i].parent) { projectiles.splice(i, 1); } } // Clean up destroyed enemies for (var i = enemies.length - 1; i >= 0; i--) { if (!enemies[i].parent) { if (enemies[i] === currentEnemy) { currentEnemy = null; } enemies.splice(i, 1); } } // Set current enemy to first alive enemy if none is set if (!currentEnemy && enemies.length > 0) { currentEnemy = enemies[0]; } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('titan', {
anchorX: 0.5,
anchorY: 0.5
});
self.maxHealth = 50;
self.health = self.maxHealth;
self.goldReward = 20;
self.isBoss = false;
self.waveNumber = 1;
// Health bar elements - will be created when enemy is spawned
self.healthBarBg = null;
self.healthBarFill = null;
self.healthText = null;
self.createHealthBar = function () {
// Health bar background - positioned at top of screen
self.healthBarBg = LK.getAsset('upgradeButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.8,
scaleY: 0.7
});
self.healthBarBg.tint = 0x333333;
self.healthBarBg.x = 1024;
self.healthBarBg.y = 200;
game.addChild(self.healthBarBg);
// Health bar fill - positioned at top of screen
self.healthBarFill = LK.getAsset('upgradeButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.8,
scaleY: 0.7
});
self.healthBarFill.tint = 0x27ae60;
self.healthBarFill.x = 1024;
self.healthBarFill.y = 200;
game.addChild(self.healthBarFill);
// Health text inside health bar - positioned at top of screen
self.healthText = new Text2(formatNumber(self.health) + '/' + formatNumber(self.maxHealth), {
size: 32,
fill: 0xFFFFFF
});
self.healthText.anchor.set(0.5, 0.5);
self.healthText.x = 1024;
self.healthText.y = 200;
game.addChild(self.healthText);
};
self.setWaveColor = function (waveNum) {
self.waveNumber = waveNum;
var colors = [0xffffff, 0xff6b6b, 0x4ecdc4, 0x45b7d1, 0x96ceb4, 0xffeaa7, 0xdda0dd, 0xff7675, 0x74b9ff, 0x00b894];
var colorIndex = (waveNum - 1) % colors.length;
enemyGraphics.tint = colors[colorIndex];
};
self.updateHealthBar = function () {
var healthPercent = self.health / self.maxHealth;
self.healthBarFill.scaleX = 1.8 * healthPercent;
if (healthPercent > 0.6) {
self.healthBarFill.tint = 0x27ae60; // Green
} else if (healthPercent > 0.3) {
self.healthBarFill.tint = 0xf39c12; // Orange
} else {
self.healthBarFill.tint = 0xe74c3c; // Red
}
// Update health text
if (self.healthText) {
self.healthText.setText(formatNumber(Math.max(0, self.health)) + '/' + formatNumber(self.maxHealth));
}
};
self.takeDamage = function (damage) {
var wasAtFullHealth = self.health === self.maxHealth;
self.health -= damage;
self.updateHealthBar();
// Get current wave color for restore
var colors = [0xffffff, 0xff6b6b, 0x4ecdc4, 0x45b7d1, 0x96ceb4, 0xffeaa7, 0xdda0dd, 0xff7675, 0x74b9ff, 0x00b894];
var colorIndex = (self.waveNumber - 1) % colors.length;
var originalColor = colors[colorIndex];
// Store original position and scale for animation reset
var originalX = enemyGraphics.x;
var originalY = enemyGraphics.y;
var originalScaleX = enemyGraphics.scaleX;
var originalScaleY = enemyGraphics.scaleY;
// Enhanced damage animation with scaling and shaking effect
tween(enemyGraphics, {
tint: 0xff0000,
scaleX: originalScaleX * 1.2,
scaleY: originalScaleY * 1.2,
x: originalX + (Math.random() - 0.5) * 20
}, {
duration: 80,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(enemyGraphics, {
tint: originalColor,
scaleX: originalScaleX,
scaleY: originalScaleY,
x: originalX,
y: originalY
}, {
duration: 120,
easing: tween.easeInOut
});
}
});
// Create damage number popup
var damageText = new Text2('-' + formatNumber(damage), {
size: 60,
fill: 0xFF0000
});
damageText.anchor.set(0.5, 0.5);
damageText.x = self.x + (Math.random() - 0.5) * 80;
damageText.y = self.y - 50;
damageText.alpha = 1;
game.addChild(damageText);
// Animate damage text floating up and fading
tween(damageText, {
y: damageText.y - 120,
alpha: 0,
scaleX: 0.7,
scaleY: 0.7
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
damageText.destroy();
}
});
if (self.health <= 0) {
// Check if this was a one-shot kill (enemy was at full health before this damage)
if (wasAtFullHealth) {
self.showHeadshotEffect();
}
self.die();
}
};
self.showHeadshotEffect = function () {
// Play headshot sound effect
if (storage.soundEnabled !== false) {
LK.getSound('headshot').play();
}
// Create headshot text
var headshotText = new Text2('HEADSHOT!', {
size: 80,
fill: 0xFFD700
});
headshotText.anchor.set(0.5, 0.5);
headshotText.x = self.x;
headshotText.y = self.y - 100;
headshotText.alpha = 1;
game.addChild(headshotText);
// Create pulsing scale effect
tween(headshotText, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(headshotText, {
scaleX: 1,
scaleY: 1,
y: headshotText.y - 80,
alpha: 0
}, {
duration: 800,
easing: tween.easeIn,
onFinish: function onFinish() {
headshotText.destroy();
}
});
}
});
// Create explosion effect with scaling circle
var explosionEffect = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.1,
scaleY: 0.1
});
explosionEffect.x = self.x;
explosionEffect.y = self.y;
explosionEffect.tint = 0xFFD700;
explosionEffect.alpha = 0.8;
game.addChild(explosionEffect);
// Animate explosion expanding and fading
tween(explosionEffect, {
scaleX: 3,
scaleY: 3,
alpha: 0
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
explosionEffect.destroy();
}
});
};
self.die = function () {
gold += self.goldReward * 2; // Increase gold reward by 2x
var crystalReward = self.isBoss ? 10 : 3;
// Increase crystal reward when wave 100 is passed
if (wave >= 100) {
crystalReward = Math.floor(crystalReward * 2.5); // 2.5x crystal multiplier for wave 100+
}
crystals += crystalReward;
updateGoldDisplay();
updateCrystalsDisplay();
if (storage.soundEnabled !== false) {
LK.getSound('enemyDeath').play();
}
// Destroy health bar elements
if (self.healthBarBg && self.healthBarBg.parent) {
self.healthBarBg.destroy();
}
if (self.healthBarFill && self.healthBarFill.parent) {
self.healthBarFill.destroy();
}
if (self.healthText && self.healthText.parent) {
self.healthText.destroy();
}
// Death animation
tween(self, {
scaleX: 0,
scaleY: 0,
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
var index = enemies.indexOf(self);
if (index > -1) {
enemies.splice(index, 1);
}
self.destroy();
spawnNextEnemy();
}
});
};
return self;
});
var Boss = Enemy.expand(function () {
var self = Enemy.call(this);
// Replace graphics with boss asset
self.removeChildren();
var bossGraphics = self.attachAsset('boss', {
anchorX: 0.5,
anchorY: 0.5
});
self.maxHealth = 5000;
self.health = self.maxHealth;
self.goldReward = 500;
self.isBoss = true;
// Override createHealthBar for boss with larger scale
self.createHealthBar = function () {
// Health bar background - positioned at top of screen
self.healthBarBg = LK.getAsset('upgradeButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.2,
scaleY: 0.8
});
self.healthBarBg.tint = 0x333333;
self.healthBarBg.x = 1024;
self.healthBarBg.y = 200;
game.addChild(self.healthBarBg);
self.healthBarFill = LK.getAsset('upgradeButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.2,
scaleY: 0.8
});
self.healthBarFill.tint = 0x8e44ad;
self.healthBarFill.x = 1024;
self.healthBarFill.y = 200;
game.addChild(self.healthBarFill);
// Health text inside boss health bar - positioned at top of screen
self.healthText = new Text2(formatNumber(self.health) + '/' + formatNumber(self.maxHealth), {
size: 36,
fill: 0xFFFFFF
});
self.healthText.anchor.set(0.5, 0.5);
self.healthText.x = 1024;
self.healthText.y = 200;
game.addChild(self.healthText);
};
// Override updateHealthBar for boss with larger scale
self.updateHealthBar = function () {
var healthPercent = self.health / self.maxHealth;
self.healthBarFill.scaleX = 2.2 * healthPercent;
if (healthPercent > 0.6) {
self.healthBarFill.tint = 0x8e44ad; // Purple for boss
} else if (healthPercent > 0.3) {
self.healthBarFill.tint = 0x9b59b6; // Lighter purple
} else {
self.healthBarFill.tint = 0xe74c3c; // Red
}
// Update health text
if (self.healthText) {
self.healthText.setText(formatNumber(Math.max(0, self.health)) + '/' + formatNumber(self.maxHealth));
}
};
var originalSetWaveColor = self.setWaveColor;
self.setWaveColor = function (waveNum) {
self.waveNumber = waveNum;
// Bosses always stay purple but get darker with higher waves
var darkness = Math.min(waveNum * 0.1, 0.7);
var baseColor = 0x8e44ad;
var r = baseColor >> 16 & 0xFF;
var g = baseColor >> 8 & 0xFF;
var b = baseColor & 0xFF;
r = Math.floor(r * (1 - darkness));
g = Math.floor(g * (1 - darkness));
b = Math.floor(b * (1 - darkness));
bossGraphics.tint = r << 16 | g << 8 | b;
};
// Override takeDamage for boss with enhanced effects
self.takeDamage = function (damage) {
var wasAtFullHealth = self.health === self.maxHealth;
self.health -= damage;
self.updateHealthBar();
// Store original position and scale for animation reset
var originalX = bossGraphics.x;
var originalY = bossGraphics.y;
var originalScaleX = bossGraphics.scaleX;
var originalScaleY = bossGraphics.scaleY;
// More dramatic boss damage animation
tween(bossGraphics, {
tint: 0xff0000,
scaleX: originalScaleX * 1.15,
scaleY: originalScaleY * 1.15,
x: originalX + (Math.random() - 0.5) * 30,
y: originalY + (Math.random() - 0.5) * 15
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(bossGraphics, {
tint: 0x8e44ad,
scaleX: originalScaleX,
scaleY: originalScaleY,
x: originalX,
y: originalY
}, {
duration: 150,
easing: tween.easeInOut
});
}
});
// Create larger damage number for boss
var damageText = new Text2('-' + formatNumber(damage), {
size: 80,
fill: 0xFF4444
});
damageText.anchor.set(0.5, 0.5);
damageText.x = self.x + (Math.random() - 0.5) * 100;
damageText.y = self.y - 80;
damageText.alpha = 1;
game.addChild(damageText);
// Animate boss damage text with more dramatic effect
tween(damageText, {
y: damageText.y - 150,
alpha: 0,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
damageText.destroy();
}
});
if (self.health <= 0) {
// Check if this was a one-shot kill (enemy was at full health before this damage)
if (wasAtFullHealth) {
self.showHeadshotEffect();
}
self.die();
}
};
// Override showHeadshotEffect for boss with more dramatic effect
self.showHeadshotEffect = function () {
// Play headshot sound effect for boss
if (storage.soundEnabled !== false) {
LK.getSound('headshot').play();
}
// Create headshot text for boss (bigger and more dramatic)
var headshotText = new Text2('BOSS HEADSHOT!', {
size: 100,
fill: 0xFF0000
});
headshotText.anchor.set(0.5, 0.5);
headshotText.x = self.x;
headshotText.y = self.y - 150;
headshotText.alpha = 1;
game.addChild(headshotText);
// Create pulsing scale effect
tween(headshotText, {
scaleX: 2,
scaleY: 2
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(headshotText, {
scaleX: 1,
scaleY: 1,
y: headshotText.y - 100,
alpha: 0
}, {
duration: 1000,
easing: tween.easeIn,
onFinish: function onFinish() {
headshotText.destroy();
}
});
}
});
// Create larger explosion effect for boss
var explosionEffect = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.1,
scaleY: 0.1
});
explosionEffect.x = self.x;
explosionEffect.y = self.y;
explosionEffect.tint = 0xFF0000;
explosionEffect.alpha = 1;
game.addChild(explosionEffect);
// Animate boss explosion expanding and fading
tween(explosionEffect, {
scaleX: 5,
scaleY: 5,
alpha: 0
}, {
duration: 700,
easing: tween.easeOut,
onFinish: function onFinish() {
explosionEffect.destroy();
}
});
};
return self;
});
var Hero = Container.expand(function () {
var self = Container.call(this);
var heroGraphics = self.attachAsset('hero', {
anchorX: 0.5,
anchorY: 0.5
});
self.level = 1;
self.damage = 5;
self.attackSpeed = 1000; // milliseconds between attacks
self.lastAttackTime = 0;
self.cost = 100;
self.type = 'DPS'; // DPS, Support, Tank
self.attack = function () {
if (currentEnemy && LK.ticks * 16.67 - self.lastAttackTime >= self.attackSpeed / gameSpeed) {
// Add hero arm animation when attacking
tween(heroGraphics, {
rotation: 0.2
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(heroGraphics, {
rotation: 0
}, {
duration: 100,
easing: tween.easeIn
});
}
});
var projectile = new HeroProjectile();
projectile.x = self.x;
projectile.y = self.y;
projectile.targetX = currentEnemy.x;
projectile.targetY = currentEnemy.y;
projectile.damage = self.damage;
projectiles.push(projectile);
game.addChild(projectile);
if (storage.soundEnabled !== false) {
LK.getSound('attack').play();
}
self.lastAttackTime = LK.ticks * 16.67;
}
};
self.upgrade = function () {
var upgradeCost = Math.floor(self.cost * Math.pow(1.15, self.level - 1));
if (gold >= upgradeCost) {
gold -= upgradeCost;
self.level++;
self.damage = Math.floor(self.damage * 1.1);
self.cost = upgradeCost;
storage.heroLevel = self.level;
updateGoldDisplay();
}
};
self.update = function () {
self.attack();
};
return self;
});
var HeroProjectile = Container.expand(function () {
var self = Container.call(this);
var projectileGraphics = self.attachAsset('heroProjectile', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.damage = 5;
self.targetX = 0;
self.targetY = 0;
self.update = function () {
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 10) {
// Hit target
if (currentEnemy) {
currentEnemy.takeDamage(self.damage);
}
var index = projectiles.indexOf(self);
if (index > -1) {
projectiles.splice(index, 1);
}
self.destroy();
} else {
// Move towards target
self.x += dx / distance * self.speed * gameSpeed;
self.y += dy / distance * self.speed * gameSpeed;
}
};
return self;
});
var SettingsPanel = Container.expand(function () {
var self = Container.call(this);
// Semi-transparent overlay
var overlay = LK.getAsset('settingsPanel', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 4,
scaleY: 4
});
overlay.tint = 0x000000;
overlay.alpha = 0.8;
overlay.x = 1024;
overlay.y = 1366;
self.addChild(overlay);
// Settings panel background
var panelBg = self.attachAsset('settingsPanel', {
anchorX: 0.5,
anchorY: 0.5
});
panelBg.x = 1024;
panelBg.y = 1366;
// Title
var titleText = new Text2('AYARLAR', {
size: 60,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 1066;
self.addChild(titleText);
// Music toggle
var musicToggle = LK.getAsset('toggleButton', {
anchorX: 0.5,
anchorY: 0.5
});
musicToggle.x = 1174;
musicToggle.y = 1200;
musicToggle.tint = storage.musicEnabled !== false ? 0x27ae60 : 0xe74c3c;
self.addChild(musicToggle);
var musicLabel = new Text2('Müzik:', {
size: 40,
fill: 0xFFFFFF
});
musicLabel.anchor.set(0, 0.5);
musicLabel.x = 774;
musicLabel.y = 1200;
self.addChild(musicLabel);
var musicText = new Text2(storage.musicEnabled !== false ? 'AÇIK' : 'KAPALI', {
size: 30,
fill: 0xFFFFFF
});
musicText.anchor.set(0.5, 0.5);
musicText.x = 1174;
musicText.y = 1200;
self.addChild(musicText);
musicToggle.down = function () {
storage.musicEnabled = !storage.musicEnabled;
musicToggle.tint = storage.musicEnabled ? 0x27ae60 : 0xe74c3c;
musicText.setText(storage.musicEnabled ? 'AÇIK' : 'KAPALI');
if (storage.musicEnabled) {
LK.playMusic('battleMusic');
} else {
LK.stopMusic();
}
};
// Sound effects toggle
var soundToggle = LK.getAsset('toggleButton', {
anchorX: 0.5,
anchorY: 0.5
});
soundToggle.x = 1174;
soundToggle.y = 1300;
soundToggle.tint = storage.soundEnabled !== false ? 0x27ae60 : 0xe74c3c;
self.addChild(soundToggle);
var soundLabel = new Text2('Efektler:', {
size: 40,
fill: 0xFFFFFF
});
soundLabel.anchor.set(0, 0.5);
soundLabel.x = 774;
soundLabel.y = 1300;
self.addChild(soundLabel);
var soundText = new Text2(storage.soundEnabled !== false ? 'AÇIK' : 'KAPALI', {
size: 30,
fill: 0xFFFFFF
});
soundText.anchor.set(0.5, 0.5);
soundText.x = 1174;
soundText.y = 1300;
self.addChild(soundText);
soundToggle.down = function () {
storage.soundEnabled = !storage.soundEnabled;
soundToggle.tint = storage.soundEnabled ? 0x27ae60 : 0xe74c3c;
soundText.setText(storage.soundEnabled ? 'AÇIK' : 'KAPALI');
};
// Language toggle
var langToggle = LK.getAsset('toggleButton', {
anchorX: 0.5,
anchorY: 0.5
});
langToggle.x = 1174;
langToggle.y = 1400;
langToggle.tint = 0x3498db;
self.addChild(langToggle);
var langLabel = new Text2('Dil:', {
size: 40,
fill: 0xFFFFFF
});
langLabel.anchor.set(0, 0.5);
langLabel.x = 774;
langLabel.y = 1400;
self.addChild(langLabel);
var langText = new Text2(storage.language || 'TR', {
size: 30,
fill: 0xFFFFFF
});
langText.anchor.set(0.5, 0.5);
langText.x = 1174;
langText.y = 1400;
self.addChild(langText);
langToggle.down = function () {
storage.language = storage.language === 'EN' ? 'TR' : 'EN';
gameLanguage = storage.language;
langText.setText(storage.language);
self.updateLanguage();
updateAllLanguageTexts();
};
// Reset game button
var resetBtn = LK.getAsset('settingsButton', {
anchorX: 0.5,
anchorY: 0.5
});
resetBtn.x = 1024;
resetBtn.y = 1500;
resetBtn.tint = 0xe74c3c;
self.addChild(resetBtn);
var resetText = new Text2('OYUNU SIFIRLA', {
size: 36,
fill: 0xFFFFFF
});
resetText.anchor.set(0.5, 0.5);
resetText.x = 1024;
resetText.y = 1500;
self.addChild(resetText);
resetBtn.down = function () {
// Reset all game state and upgrades
storage.gold = 500;
storage.crystals = 10;
storage.wave = 1;
storage.currentDPS = 0;
delete storage.heroLevel;
delete storage.prestigeMultiplier;
LK.showGameOver();
};
// Close button
var closeBtn = LK.getAsset('settingsButton', {
anchorX: 0.5,
anchorY: 0.5
});
closeBtn.x = 1024;
closeBtn.y = 1600;
closeBtn.tint = 0x95a5a6;
self.addChild(closeBtn);
var closeText = new Text2('KAPAT', {
size: 36,
fill: 0xFFFFFF
});
closeText.anchor.set(0.5, 0.5);
closeText.x = 1024;
closeText.y = 1600;
self.addChild(closeText);
closeBtn.down = function () {
self.hide();
};
self.updateLanguage = function () {
var isEn = storage.language === 'EN';
titleText.setText(isEn ? 'SETTINGS' : 'AYARLAR');
musicLabel.setText(isEn ? 'Music:' : 'Müzik:');
soundLabel.setText(isEn ? 'Effects:' : 'Efektler:');
langLabel.setText(isEn ? 'Language:' : 'Dil:');
musicText.setText(storage.musicEnabled !== false ? isEn ? 'ON' : 'AÇIK' : isEn ? 'OFF' : 'KAPALI');
soundText.setText(storage.soundEnabled !== false ? isEn ? 'ON' : 'AÇIK' : isEn ? 'OFF' : 'KAPALI');
resetText.setText(isEn ? 'RESET GAME' : 'OYUNU SIFIRLA');
closeText.setText(isEn ? 'CLOSE' : 'KAPAT');
};
self.show = function () {
self.alpha = 1;
self.visible = true;
game.isPaused = true;
// Bring settings panel to front to ensure it's on top
if (self.parent) {
self.parent.setChildIndex(self, self.parent.children.length - 1);
}
// Also ensure overlay is on top
if (overlay.parent) {
overlay.parent.setChildIndex(overlay, overlay.parent.children.length - 1);
}
// And ensure panel background is on top
if (panelBg.parent) {
panelBg.parent.setChildIndex(panelBg, panelBg.parent.children.length - 1);
}
// Bring all text and buttons to front to ensure they're above the panel
if (titleText.parent) {
titleText.parent.setChildIndex(titleText, titleText.parent.children.length - 1);
}
if (musicToggle.parent) {
musicToggle.parent.setChildIndex(musicToggle, musicToggle.parent.children.length - 1);
}
if (musicLabel.parent) {
musicLabel.parent.setChildIndex(musicLabel, musicLabel.parent.children.length - 1);
}
if (musicText.parent) {
musicText.parent.setChildIndex(musicText, musicText.parent.children.length - 1);
}
if (soundToggle.parent) {
soundToggle.parent.setChildIndex(soundToggle, soundToggle.parent.children.length - 1);
}
if (soundLabel.parent) {
soundLabel.parent.setChildIndex(soundLabel, soundLabel.parent.children.length - 1);
}
if (soundText.parent) {
soundText.parent.setChildIndex(soundText, soundText.parent.children.length - 1);
}
if (langToggle.parent) {
langToggle.parent.setChildIndex(langToggle, langToggle.parent.children.length - 1);
}
if (langLabel.parent) {
langLabel.parent.setChildIndex(langLabel, langLabel.parent.children.length - 1);
}
if (langText.parent) {
langText.parent.setChildIndex(langText, langText.parent.children.length - 1);
}
if (resetBtn.parent) {
resetBtn.parent.setChildIndex(resetBtn, resetBtn.parent.children.length - 1);
}
if (resetText.parent) {
resetText.parent.setChildIndex(resetText, resetText.parent.children.length - 1);
}
if (closeBtn.parent) {
closeBtn.parent.setChildIndex(closeBtn, closeBtn.parent.children.length - 1);
}
if (closeText.parent) {
closeText.parent.setChildIndex(closeText, closeText.parent.children.length - 1);
}
};
self.hide = function () {
self.alpha = 0;
self.visible = false;
game.isPaused = false;
};
// Start hidden
self.hide();
return self;
});
var TutorialPanel = Container.expand(function () {
var self = Container.call(this);
// Semi-transparent overlay
var overlay = LK.getAsset('settingsPanel', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 4,
scaleY: 4
});
overlay.tint = 0x000000;
overlay.alpha = 0.9;
overlay.x = 1024;
overlay.y = 1366;
self.addChild(overlay);
// Tutorial panel background
var panelBg = self.attachAsset('settingsPanel', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.3
});
panelBg.x = 1024;
panelBg.y = 1366;
// Title
var titleText = new Text2('OYUNU ÖĞRENİN', {
size: 60,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 1000;
self.addChild(titleText);
// Tutorial content
var tutorialText = new Text2('• Ekrana dokunarak altın kazanın\n• Altınla kahramanınızı güçlendirin\n• Dalgaları geçip kristal toplayın\n• 1000 kristalle prestij yapın\n• Bossları yenip ilerleyin!', {
size: 36,
fill: 0xFFFFFF
});
tutorialText.anchor.set(0.5, 0.5);
tutorialText.x = 1024;
tutorialText.y = 1300;
self.addChild(tutorialText);
// Gold tap hint
var tapHintText = new Text2('💰 EKRANA DOKUNUN = ALTIN 💰', {
size: 40,
fill: 0xFFD700
});
tapHintText.anchor.set(0.5, 0.5);
tapHintText.x = 1024;
tapHintText.y = 1500;
self.addChild(tapHintText);
// Close button (X)
var closeBtn = LK.getAsset('settingsIcon', {
anchorX: 0.5,
anchorY: 0.5
});
closeBtn.x = 1300;
closeBtn.y = 900;
closeBtn.tint = 0xe74c3c;
self.addChild(closeBtn);
var closeText = new Text2('✕', {
size: 50,
fill: 0xFFFFFF
});
closeText.anchor.set(0.5, 0.5);
closeBtn.addChild(closeText);
closeBtn.down = function () {
self.hide();
};
self.show = function () {
self.alpha = 1;
self.visible = true;
game.isPaused = true;
};
self.updateLanguage = function () {
titleText.setText(getText('learnGame'));
tutorialText.setText(getText('tutorialText'));
tapHintText.setText(getText('tapHint'));
};
self.hide = function () {
self.alpha = 0;
self.visible = false;
game.isPaused = false;
// Mark tutorial as seen
storage.tutorialSeen = true;
};
// Start visible
self.alpha = 1;
self.visible = true;
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2c3e50
});
/****
* Game Code
****/
// Add background image
var backgroundImage = LK.getAsset('background', {
anchorX: 0,
anchorY: 0
});
backgroundImage.x = 0;
backgroundImage.y = 0;
game.addChild(backgroundImage);
// Reset game state - clear all storage
storage.gold = 500;
storage.crystals = 10;
storage.wave = 1;
storage.currentDPS = 0;
storage.prestigeMultiplier = 1;
delete storage.heroLevel;
delete storage.autoUpgradeEnabled;
delete storage.autoClickEnabled;
delete storage.gameSpeed;
delete storage.tutorialSeen;
// Game state variables
var gold = 500;
var crystals = 10;
var wave = 1;
var currentDPS = 0;
var prestigeMultiplier = 1;
var heroes = [];
var enemies = [];
var projectiles = [];
var currentEnemy = null;
// UI elements
var goldText = new Text2('Gold: ' + gold, {
size: 40,
fill: 0xFFD700
});
goldText.anchor.set(0, 0);
goldText.x = 120;
goldText.y = 50;
// Add to game but will be moved to top layer in update function
game.addChild(goldText);
var crystalsText = new Text2('Crystals: ' + crystals, {
size: 40,
fill: 0x9B59B6
});
crystalsText.anchor.set(0, 0);
crystalsText.x = 120;
crystalsText.y = 100;
// Add to game but will be moved to top layer in update function
game.addChild(crystalsText);
var waveText = new Text2('Wave: ' + wave, {
size: 50,
fill: 0xFFFFFF
});
waveText.anchor.set(0.5, 0);
waveText.x = 1024;
waveText.y = 50;
// Add to game but will be moved to top layer in update function
game.addChild(waveText);
var dpsText = new Text2('DPS: ' + currentDPS, {
size: 40,
fill: 0xE74C3C
});
dpsText.anchor.set(1, 0);
dpsText.x = 1928;
dpsText.y = 50;
// Add to game but will be moved to top layer in update function
game.addChild(dpsText);
var prestigePointsText = new Text2('Prestige: ' + Math.floor(prestigeMultiplier * 100 - 100) + ' (' + prestigeMultiplier.toFixed(1) + 'x)', {
size: 35,
fill: 0x9B59B6
});
prestigePointsText.anchor.set(1, 0);
prestigePointsText.x = 1928;
prestigePointsText.y = 100;
// Add to game but will be moved to top layer in update function
game.addChild(prestigePointsText);
// Damage upgrade button
var upgradeBtn = LK.getAsset('upgradeButton', {
anchorX: 0.5,
anchorY: 0.5
});
upgradeBtn.x = -260;
upgradeBtn.y = -40;
LK.gui.bottom.addChild(upgradeBtn);
var upgradeBtnText = new Text2('Upgrade Damage\n100 Gold', {
size: 22,
fill: 0xFFFFFF
});
upgradeBtnText.anchor.set(0.5, 0.5);
upgradeBtnText.x = 0;
upgradeBtnText.y = 0;
upgradeBtn.addChild(upgradeBtnText);
upgradeBtn.down = function () {
if (heroes.length > 0) {
var baseCost = 100; // Use fixed base cost
var upgradeCost = Math.floor(baseCost * Math.pow(1.15, heroes[0].level - 1));
if (gold >= upgradeCost) {
gold -= upgradeCost;
heroes[0].level++;
heroes[0].damage = Math.floor(heroes[0].damage * 1.2); // Increase damage by 20% per upgrade
storage.heroLevel = heroes[0].level;
updateGoldDisplay();
updateUpgradeButton();
}
}
};
// Auto upgrade button
var autoUpgradeBtn = LK.getAsset('upgradeButton', {
anchorX: 0.5,
anchorY: 0.5
});
autoUpgradeBtn.x = -60;
autoUpgradeBtn.y = -40;
LK.gui.bottom.addChild(autoUpgradeBtn);
var autoUpgradeBtnText = new Text2('Auto\nOFF', {
size: 22,
fill: 0xFFFFFF
});
autoUpgradeBtnText.anchor.set(0.5, 0.5);
autoUpgradeBtnText.x = 0;
autoUpgradeBtnText.y = 0;
autoUpgradeBtn.addChild(autoUpgradeBtnText);
// Auto upgrade state
var autoUpgradeEnabled = false;
var autoUpgradeLastCheck = 0;
// Auto click button
var autoClickBtn = LK.getAsset('upgradeButton', {
anchorX: 0.5,
anchorY: 0.5
});
autoClickBtn.x = 50;
autoClickBtn.y = 0;
LK.gui.left.addChild(autoClickBtn);
var autoClickBtnText = new Text2('Auto\nClick\nOFF', {
size: 18,
fill: 0xFFFFFF
});
autoClickBtnText.anchor.set(0.5, 0.5);
autoClickBtnText.x = 0;
autoClickBtnText.y = 0;
autoClickBtn.addChild(autoClickBtnText);
// Auto click state
var autoClickEnabled = false;
var autoClickLastTime = 0;
var autoClickInterval = 1000; // Click every 1000ms (1 time per second)
// Update auto upgrade button display
function updateAutoUpgradeButton() {
if (autoUpgradeEnabled) {
autoUpgradeBtn.tint = 0x27ae60; // Green when enabled
autoUpgradeBtnText.setText('Auto\nON');
} else {
autoUpgradeBtn.tint = 0xe74c3c; // Red when disabled
autoUpgradeBtnText.setText('Auto\nOFF');
}
}
// Update auto click button display
function updateAutoClickButton() {
if (autoClickEnabled) {
autoClickBtn.tint = 0x27ae60; // Green when enabled
autoClickBtnText.setText('Auto\nClick\nON');
} else {
autoClickBtn.tint = 0xe74c3c; // Red when disabled
autoClickBtnText.setText('Auto\nClick\nOFF');
}
}
// Initialize auto upgrade button state
updateAutoUpgradeButton();
autoUpgradeBtn.down = function () {
autoUpgradeEnabled = !autoUpgradeEnabled;
storage.autoUpgradeEnabled = autoUpgradeEnabled;
updateAutoUpgradeButton();
};
// Initialize auto click button state
updateAutoClickButton();
autoClickBtn.down = function () {
autoClickEnabled = !autoClickEnabled;
storage.autoClickEnabled = autoClickEnabled;
updateAutoClickButton();
};
// Auto upgrade function
function performAutoUpgrade() {
if (!autoUpgradeEnabled || heroes.length === 0) {
return;
}
var baseCost = 100;
var upgradeCost = Math.floor(baseCost * Math.pow(1.15, heroes[0].level - 1));
if (gold >= upgradeCost) {
gold -= upgradeCost;
heroes[0].level++;
heroes[0].damage = Math.floor(heroes[0].damage * 1.2);
storage.heroLevel = heroes[0].level;
updateGoldDisplay();
updateUpgradeButton();
}
}
// Summon button removed - hero çağır butonunu kaldır
// Prestige button
var prestigeBtn = LK.getAsset('summonButton', {
anchorX: 0.5,
anchorY: 0.5
});
prestigeBtn.x = 120;
prestigeBtn.y = -40;
LK.gui.bottom.addChild(prestigeBtn);
var prestigeBtnText = new Text2(getText('Prestige') + '\n' + formatNumber(500) + ' ' + getText('Crystals'), {
size: 24,
fill: 0xFFFFFF
});
prestigeBtnText.anchor.set(0.5, 0.5);
prestigeBtnText.x = 0;
prestigeBtnText.y = 0;
prestigeBtn.addChild(prestigeBtnText);
prestigeBtn.down = function () {
if (crystals >= 500) {
crystals -= 500;
doPrestige();
updateCrystalsDisplay();
}
};
// Game speed control
var gameSpeed = 1;
var gameSpeedMultipliers = [1, 2];
var gameSpeedButton = LK.getAsset('toggleButton', {
anchorX: 0.5,
anchorY: 0.5
});
gameSpeedButton.x = -50;
gameSpeedButton.y = -120;
LK.gui.bottomRight.addChild(gameSpeedButton);
var gameSpeedText = new Text2(gameSpeed + 'x', {
size: 30,
fill: 0xFFFFFF
});
gameSpeedText.anchor.set(0.5, 0.5);
gameSpeedText.x = 0;
gameSpeedText.y = 0;
gameSpeedButton.addChild(gameSpeedText);
gameSpeedButton.down = function () {
var currentIndex = gameSpeedMultipliers.indexOf(gameSpeed);
var nextIndex = (currentIndex + 1) % gameSpeedMultipliers.length;
gameSpeed = gameSpeedMultipliers[nextIndex];
storage.gameSpeed = gameSpeed;
gameSpeedText.setText(gameSpeed + 'x');
};
// Settings icon in bottom right
var settingsIcon = LK.getAsset('settingsIcon', {
anchorX: 0.5,
anchorY: 0.5
});
settingsIcon.x = -50;
settingsIcon.y = -50;
LK.gui.bottomRight.addChild(settingsIcon);
var settingsText = new Text2('⚙', {
size: 50,
fill: 0xFFFFFF
});
settingsText.anchor.set(0.5, 0.5);
settingsText.x = 0;
settingsText.y = 0;
settingsIcon.addChild(settingsText);
// Settings panel
var settingsPanel = new SettingsPanel();
game.addChild(settingsPanel);
settingsIcon.down = function () {
settingsPanel.show();
};
// Tutorial panel - show only once for new players
var tutorialPanel = new TutorialPanel();
game.addChild(tutorialPanel);
// Show tutorial for fresh start
tutorialPanel.show();
game.isPaused = true;
// Language system
var gameLanguage = storage.language || 'TR';
var languageTexts = {
TR: {
gold: 'Altın',
crystals: 'Kristal',
wave: 'Dalga',
dps: 'DPS',
upgradeDamage: 'Hasarı Yükselt',
prestige: 'Prestij',
settings: 'AYARLAR',
music: 'Müzik:',
effects: 'Efektler:',
language: 'Dil:',
on: 'AÇIK',
off: 'KAPALI',
resetGame: 'OYUNU SIFIRLA',
close: 'KAPAT',
learnGame: 'OYUNU ÖĞRENİN',
tutorialText: '• Ekrana dokunarak altın kazanın\n• Altınla kahramanınızı güçlendirin\n• Dalgaları geçip kristal toplayın\n• 1000 kristalle prestij yapın\n• Bossları yenip ilerleyin!',
tapHint: '🏆 EKRANA DOKUNUN = ALTIN',
gold_unit: 'Altın',
crystals_unit: 'Kristal'
},
EN: {
gold: 'Gold',
crystals: 'Crystals',
wave: 'Wave',
dps: 'DPS',
upgradeDamage: 'Upgrade Damage',
prestige: 'Prestige',
settings: 'SETTINGS',
music: 'Music:',
effects: 'Effects:',
language: 'Language:',
on: 'ON',
off: 'OFF',
resetGame: 'RESET GAME',
close: 'CLOSE',
learnGame: 'LEARN THE GAME',
tutorialText: '• Tap screen to earn gold\n• Use gold to upgrade your hero\n• Beat waves to collect crystals\n• Prestige with 1000 crystals\n• Defeat bosses to progress!',
tapHint: '🏆 TAP SCREEN = GOLD',
gold_unit: 'Gold',
crystals_unit: 'Crystals'
}
};
function getText(key) {
// Ensure languageTexts object exists
if (!languageTexts) {
return key;
}
// Ensure gameLanguage is valid, default to 'TR' if not
var lang = gameLanguage && languageTexts[gameLanguage] ? gameLanguage : 'TR';
// Safely access language texts with fallbacks
if (languageTexts[lang] && languageTexts[lang][key]) {
return languageTexts[lang][key];
}
if (languageTexts.TR && languageTexts.TR[key]) {
return languageTexts.TR[key];
}
return key; // Return the key itself as fallback
}
// Number formatting function for global abbreviations
function formatNumber(num) {
if (num < 1000) {
return num.toString();
}
if (num < 1000000) {
return (num / 1000).toFixed(1) + 'K';
}
if (num < 1000000000) {
return (num / 1000000).toFixed(1) + 'M';
}
if (num < 1000000000000) {
return (num / 1000000000).toFixed(1) + 'B';
}
if (num < 1000000000000000) {
return (num / 1000000000000).toFixed(1) + 'T';
}
if (num < 1000000000000000000) {
return (num / 1000000000000000).toFixed(1) + 'Q';
}
return (num / 1000000000000000000).toFixed(1) + 'Qi';
}
// Game functions
function updateGoldDisplay() {
goldText.setText(getText('gold') + ': ' + formatNumber(gold));
storage.gold = gold;
}
function updateCrystalsDisplay() {
crystalsText.setText(getText('crystals') + ': ' + formatNumber(crystals));
storage.crystals = crystals;
}
function updateWaveDisplay() {
waveText.setText(getText('wave') + ': ' + formatNumber(wave));
storage.wave = wave;
}
function updateDPSDisplay() {
var totalDPS = 0;
for (var i = 0; i < heroes.length; i++) {
totalDPS += Math.floor(heroes[i].damage * 1000 / heroes[i].attackSpeed);
}
currentDPS = totalDPS;
storage.currentDPS = currentDPS;
dpsText.setText(getText('dps') + ': ' + formatNumber(totalDPS));
}
function updatePrestigePointsDisplay() {
var points = Math.floor(prestigeMultiplier * 100 - 100);
prestigePointsText.setText('Prestij: ' + points + ' (' + prestigeMultiplier.toFixed(1) + 'x)');
}
function updateUpgradeButton() {
if (heroes.length > 0) {
var baseCost = 100; // Use fixed base cost instead of hero.cost
var cost = Math.floor(baseCost * Math.pow(1.15, heroes[0].level));
upgradeBtnText.setText(getText('upgradeDamage') + '\n' + formatNumber(cost) + ' ' + getText('gold_unit'));
}
}
function updateAllLanguageTexts() {
// Update main UI displays
updateGoldDisplay();
updateCrystalsDisplay();
updateWaveDisplay();
updateDPSDisplay();
updatePrestigePointsDisplay();
updateUpgradeButton();
// Update prestige button
prestigeBtnText.setText(getText('prestige') + '\n' + formatNumber(500) + ' ' + getText('crystals_unit'));
// Update settings panel if it exists
if (settingsPanel && settingsPanel.updateLanguage) {
settingsPanel.updateLanguage();
}
// Update tutorial panel if it exists
if (tutorialPanel && tutorialPanel.updateLanguage) {
tutorialPanel.updateLanguage();
}
}
function summonHero() {
var hero = new Hero();
hero.x = 300 + heroes.length * 100;
hero.y = 1800;
// Apply stored upgrade levels
if (storage.heroLevel) {
hero.level = storage.heroLevel;
hero.damage = Math.floor(10 * Math.pow(1.1, hero.level - 1) * prestigeMultiplier);
}
// Apply prestige multiplier to new heroes
hero.damage = Math.floor(hero.damage * prestigeMultiplier);
heroes.push(hero);
game.addChild(hero);
}
function doPrestige() {
// Increase prestige multiplier by 1.2x
prestigeMultiplier *= 1.2;
storage.prestigeMultiplier = prestigeMultiplier;
// Reset all game state
gold = 500;
crystals = 10;
wave = 1;
currentDPS = 0;
// Clear all game objects
for (var i = heroes.length - 1; i >= 0; i--) {
heroes[i].destroy();
}
heroes = [];
for (var i = enemies.length - 1; i >= 0; i--) {
enemies[i].destroy();
}
enemies = [];
currentEnemy = null;
for (var i = projectiles.length - 1; i >= 0; i--) {
projectiles[i].destroy();
}
projectiles = [];
// Clear storage upgrades (reset upgrades on prestige)
delete storage.heroLevel;
// Update storage with reset values
storage.gold = gold;
storage.crystals = crystals;
storage.wave = wave;
storage.currentDPS = currentDPS;
// Update displays
updateGoldDisplay();
updateCrystalsDisplay();
updateWaveDisplay();
updateDPSDisplay();
updatePrestigePointsDisplay();
// Restart the game with prestige bonus
summonHero();
spawnEnemy();
}
function spawnEnemy() {
// Don't spawn if there are already enemies alive
if (enemies.length > 0 || currentEnemy) {
return;
}
var enemy;
if (wave % 10 === 0) {
// Boss wave - only spawn boss
enemy = new Boss();
enemy.maxHealth = Math.floor(250 * Math.pow(5.0, Math.floor(wave / 10)));
} else {
// Regular wave - spawn single titan
enemy = new Enemy();
enemy.maxHealth = Math.floor(50 * Math.pow(1.15, wave));
}
enemy.health = enemy.maxHealth;
enemy.goldReward = Math.floor(enemy.goldReward * Math.pow(1.1, wave));
enemy.setWaveColor(wave);
enemy.createHealthBar();
enemy.updateHealthBar();
enemy.x = 1500;
enemy.y = 1800;
enemies.push(enemy);
game.addChild(enemy);
currentEnemy = enemy;
}
function spawnNextEnemy() {
// Clear current enemy reference
currentEnemy = null;
// Always spawn next enemy after a small delay
LK.setTimeout(function () {
// Check if we should proceed to next wave
if (enemies.length === 0) {
wave++;
updateWaveDisplay();
}
spawnEnemy();
}, 1000 / gameSpeed);
}
// Initialize first hero and enemy
summonHero();
spawnEnemy();
// Start background music
if (storage.musicEnabled !== false) {
LK.playMusic('battleMusic');
}
// Click rate limiting variables
var clickTimes = [];
var maxClicksPerSecond = 10;
var maxTotalClicksPerSecond = 20;
// Hold state variables
var isHolding = false;
var holdStartTime = 0;
var lastGoldGenTime = 0;
var goldPerSecondWhileHolding = 5; // Generate 5 gold per second while holding
// Screen tap handler for gold generation
game.down = function (x, y, obj) {
// Only give gold if game is not paused
if (!game.isPaused) {
var currentTime = Date.now();
// Clean up old click times (older than 1 second)
clickTimes = clickTimes.filter(function (time) {
return currentTime - time < 1000;
});
// Check if we've exceeded the click limits
if (clickTimes.length >= maxTotalClicksPerSecond) {
return; // Block the click if we've hit the 20 clicks per second limit
}
// Check if we've exceeded 10 clicks in the last 100ms (to ensure max 10 clicks per second rate)
var recentClicks = clickTimes.filter(function (time) {
return currentTime - time < 100;
});
if (recentClicks.length >= 1) {
return; // Block the click if we've already clicked in the last 100ms
}
// Record this click time
clickTimes.push(currentTime);
// Start holding state
isHolding = true;
holdStartTime = currentTime;
lastGoldGenTime = currentTime;
var tapGold = Math.floor((2 + wave * 1) * prestigeMultiplier);
// Increase tap gold by 1.5x when wave 100 is passed
if (wave >= 100) {
tapGold = Math.floor(tapGold * 1.5);
}
gold += tapGold;
updateGoldDisplay();
// Create gold icon animation
var goldIcon = LK.getAsset('goldIcon', {
anchorX: 0.5,
anchorY: 0.5
});
goldIcon.x = x;
goldIcon.y = y;
goldIcon.alpha = 1;
game.addChild(goldIcon);
// Animate gold icon moving up and fading out
tween(goldIcon, {
y: y - 100,
alpha: 0
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
goldIcon.destroy();
}
});
}
};
// Screen release handler
game.up = function (x, y, obj) {
isHolding = false;
};
// Main game loop
game.update = function () {
// Skip update if game is paused
if (game.isPaused) {
return;
}
// Check for wave 100 attack speed boost
if (wave >= 100) {
// Apply 1.25x attack speed boost to all heroes
for (var i = 0; i < heroes.length; i++) {
if (!heroes[i].speedBoosted) {
heroes[i].attackSpeed = Math.floor(heroes[i].attackSpeed / 1.25);
heroes[i].speedBoosted = true;
}
}
}
// Handle continuous gold generation while holding
if (isHolding) {
var currentTime = Date.now();
var timeSinceLastGold = currentTime - lastGoldGenTime;
// Generate gold every 200ms (5 times per second)
if (timeSinceLastGold >= 200) {
var holdGold = Math.floor((1 + wave * 0.5) * prestigeMultiplier);
gold += holdGold;
updateGoldDisplay();
lastGoldGenTime = currentTime;
// Create small gold icon animation at random position
var goldIcon = LK.getAsset('goldIcon', {
anchorX: 0.5,
anchorY: 0.5
});
goldIcon.x = 800 + Math.random() * 400; // Random x between 800-1200
goldIcon.y = 1000 + Math.random() * 400; // Random y between 1000-1400
goldIcon.alpha = 0.8;
goldIcon.scaleX = 0.7;
goldIcon.scaleY = 0.7;
game.addChild(goldIcon);
// Animate small gold icon
tween(goldIcon, {
y: goldIcon.y - 50,
alpha: 0
}, {
duration: 600,
easing: tween.easeOut,
onFinish: function onFinish() {
goldIcon.destroy();
}
});
}
}
// Update displays
updateDPSDisplay();
updatePrestigePointsDisplay();
updateUpgradeButton();
// Move UI texts to top layer every frame to ensure they stay on top
if (goldText && goldText.parent) {
goldText.parent.setChildIndex(goldText, goldText.parent.children.length - 1);
}
if (crystalsText && crystalsText.parent) {
crystalsText.parent.setChildIndex(crystalsText, crystalsText.parent.children.length - 1);
}
if (waveText && waveText.parent) {
waveText.parent.setChildIndex(waveText, waveText.parent.children.length - 1);
}
if (dpsText && dpsText.parent) {
dpsText.parent.setChildIndex(dpsText, dpsText.parent.children.length - 1);
}
if (prestigePointsText && prestigePointsText.parent) {
prestigePointsText.parent.setChildIndex(prestigePointsText, prestigePointsText.parent.children.length - 1);
}
// Auto upgrade check (every 100ms to avoid lag)
if (LK.ticks % 6 === 0) {
performAutoUpgrade();
}
// Auto click check (every 60 ticks = 1 second)
if (autoClickEnabled && LK.ticks % 60 === 0) {
var currentTime = Date.now();
if (currentTime - autoClickLastTime >= 1000) {
// Give 1 gold per second
var tapGold = 1;
gold += tapGold;
updateGoldDisplay();
autoClickLastTime = currentTime;
// Create gold icon animation at random position
var goldIcon = LK.getAsset('goldIcon', {
anchorX: 0.5,
anchorY: 0.5
});
goldIcon.x = 800 + Math.random() * 400; // Random x between 800-1200
goldIcon.y = 1000 + Math.random() * 400; // Random y between 1000-1400
goldIcon.alpha = 0.8;
goldIcon.scaleX = 0.7;
goldIcon.scaleY = 0.7;
game.addChild(goldIcon);
// Animate gold icon
tween(goldIcon, {
y: goldIcon.y - 50,
alpha: 0
}, {
duration: 600,
easing: tween.easeOut,
onFinish: function onFinish() {
goldIcon.destroy();
}
});
}
}
// Clean up destroyed projectiles
for (var i = projectiles.length - 1; i >= 0; i--) {
if (!projectiles[i].parent) {
projectiles.splice(i, 1);
}
}
// Clean up destroyed enemies
for (var i = enemies.length - 1; i >= 0; i--) {
if (!enemies[i].parent) {
if (enemies[i] === currentEnemy) {
currentEnemy = null;
}
enemies.splice(i, 1);
}
}
// Set current enemy to first alive enemy if none is set
if (!currentEnemy && enemies.length > 0) {
currentEnemy = enemies[0];
}
};
Büyücü. In-Game asset. 2d. High contrast. No shadows
Titan enemy. In-Game asset. 2d. High contrast. No shadows
Boss Titan. In-Game asset. 2d. High contrast. No shadows
GOLD. In-Game asset. 2d. High contrast. No shadows
doğa. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
fireball. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat