User prompt
Evet. Ödülde olduğu gibi, Saldırı ve savunma da 10 katı olsun. Hareket hızı ve ekranda dolaşım sistemi diğer korsanlar ile aynı olsun.
User prompt
Katil hareket hızı ve yapay zeka tepki durumu diğer korsan gemileri gibi olsun.
User prompt
Katil'in hareket sistemi tamamen normal korsan gibi olsun. Şuan ki farklı hareket ediyor.
User prompt
Katil'in üstünde ismi ve alacağımız "Ödül:" yazsın.
User prompt
Katil, 10 ila 60 saniye aralığında 1 tane normal korsan gibi ekranın bir yerinde spawn olsun haritada gezsin.
User prompt
Hammadde Takası panelinin açılış konumunu 2 satır aşağı kaydır.
User prompt
Hammadde Takası panelini olduğu gibi 2 satır aşağı kaydır.
User prompt
Panellerin tamamının sadece kapat butonunu %30 oranında büyüt.
User prompt
Panellerin, kapat butonlarının boyutunu ve işlev alanını %25 büyüt
User prompt
Hammadde Takası panelini 1 satır aşağı kaydır
User prompt
Oyunda spawn olan asteroid sayısını yarı yarıya düşür.
User prompt
Panel kapanınca, stok yazısı otomatik gizlensin.
User prompt
Uzay istasyonu panel içerisinde stok durumu yazsın.
User prompt
Gemiyi ekranın ortasında duracak şekilde ayarla. Harita da o şekilde gezelim.
User prompt
Gemi harita dışına çıkmayacak şekilde ekranın ortasında dursun. O şekilde hareket edelim.
User prompt
Oyunda ölüm sistemini geri getir. Onu yaptıktan sonra oyun bozuldu joistik çalışmaz oldu.
User prompt
Sol üstte bulunan oyunu durdur çalışmıyor. Sol altta bulunan joystick çalışmıyor. Hiçbir şekilde tıklama yapamıyorum bunlara.
User prompt
Son zamanlarda istasyon istekler paneli hakkında fix yaptın. Yaptıktan sonra oyuncu gemisi ve joystick hareket etmez oldu. Ne gibi değişiklikler yapıldı? İnceler misin nedir bu problem.
User prompt
Oyuncu gemisi hareket sistemini kontrol et. Gerekirse sil ve yeniden kod oluştur.
User prompt
Son 1 saat içinde eklenmiş kodları sil.
User prompt
Gemi kontrol mekanizması neden çalışmıyor? Dokunsam bile işlemiyor.
User prompt
Gemi kontrol mekanizması çalışmıyor.
User prompt
Reset butonu yakınlarında ki istasyon butonunu gizle.
User prompt
Joystick neden hareket ettiremiyorum? Kontrol et düzenle.
User prompt
Gemi hareket etmiyor
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var Asteroid = Container.expand(function () { var self = Container.call(this); var asteroidGraphics = self.attachAsset('resource', { anchorX: 0.5, anchorY: 0.5, tint: 0x8B4513, scaleX: 2, scaleY: 2 }); self.health = 50; self.resources = Math.floor(Math.random() * 10) + 5; self.vx = (Math.random() - 0.5) * 0.5; self.vy = (Math.random() - 0.5) * 0.5; self.rotationSpeed = (Math.random() - 0.5) * 0.02; self.takeDamage = function (amount) { self.health -= amount; LK.effects.flashObject(self, 0xffffff, 100); }; self.update = function () { self.x += self.vx; self.y += self.vy; self.rotation += self.rotationSpeed; }; return self; }); // Black Hole Hazard Class var BlackHole = Container.expand(function () { var self = Container.call(this); var bhGraphics = self.attachAsset('star', { anchorX: 0.5, anchorY: 0.5, scaleX: 8, scaleY: 8, tint: 0x222222 }); self.radius = 200; self.pullStrength = 0.7 + Math.random() * 0.5; self.damageRadius = 120; self.update = function () { // Animate black hole bhGraphics.rotation += 0.03; // Pull ship if in range var dx = ship.x - self.x; var dy = ship.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < self.radius) { var pull = (self.radius - dist) / self.radius * self.pullStrength; ship.x -= dx / dist * pull; ship.y -= dy / dist * pull; // Camera follows ship, so move all objects accordingly for (var i = 0; i < stars.length; i++) { stars[i].x -= dx / dist * pull; stars[i].y -= dy / dist * pull; } for (var i = 0; i < npcs.length; i++) { npcs[i].x -= dx / dist * pull; npcs[i].y -= dy / dist * pull; } for (var i = 0; i < pirates.length; i++) { pirates[i].x -= dx / dist * pull; pirates[i].y -= dy / dist * pull; } for (var i = 0; i < coins.length; i++) { coins[i].x -= dx / dist * pull; coins[i].y -= dy / dist * pull; } for (var i = 0; i < resources.length; i++) { resources[i].x -= dx / dist * pull; resources[i].y -= dy / dist * pull; } for (var i = 0; i < bullets.length; i++) { bullets[i].x -= dx / dist * pull; bullets[i].y -= dy / dist * pull; } for (var i = 0; i < enemyBullets.length; i++) { enemyBullets[i].x -= dx / dist * pull; enemyBullets[i].y -= dy / dist * pull; } for (var i = 0; i < asteroids.length; i++) { asteroids[i].x -= dx / dist * pull; asteroids[i].y -= dy / dist * pull; } for (var i = 0; i < upgradeStations.length; i++) { upgradeStations[i].x -= dx / dist * pull; upgradeStations[i].y -= dy / dist * pull; } // boostParticles removed (no boost system) for (var i = 0; i < explosions.length; i++) { explosions[i].x -= dx / dist * pull; explosions[i].y -= dy / dist * pull; } } // Damage ship if too close if (dist < self.damageRadius) { if (!self.lastDamaged || LK.ticks - self.lastDamaged > 30) { ship.takeDamage(10); self.lastDamaged = LK.ticks; LK.effects.flashObject(ship, 0x000000, 200); } } }; return self; }); var Bullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 15; self.damage = 10; self.directionX = 0; self.directionY = -1; self.update = function () { self.x += self.directionX * self.speed; self.y += self.directionY * self.speed; }; return self; }); var Coin = Container.expand(function () { var self = Container.call(this); var coinGraphics = self.attachAsset('coin', { anchorX: 0.5, anchorY: 0.5 }); self.value = Math.floor(Math.random() * 10) + 5; self.update = function () { self.rotation += 0.05; }; return self; }); var EnemyBullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('enemyBullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 8; self.damage = 5; self.directionX = 0; self.directionY = 0; self.update = function () { self.x += self.directionX * self.speed; self.y += self.directionY * self.speed; }; return self; }); // HealthBar class for displaying health above entities var HealthBar = Container.expand(function () { var self = Container.call(this); // width, height, color, maxValue, getValueFn self._width = 60; self._height = 10; self._color = 0x00ff00; self._maxValue = 100; self._getValueFn = null; self._getMaxFn = null; self._bg = self.attachAsset('resource', { anchorX: 0.5, anchorY: 0.5, scaleX: self._width / 40, scaleY: self._height / 40, tint: 0x222222 }); self._bar = self.attachAsset('resource', { anchorX: 0.5, anchorY: 0.5, scaleX: (self._width - 4) / 40, scaleY: (self._height - 4) / 40, tint: self._color }); self._bar.x = 0; self._bar.y = 0; self.set = function (opts) { self._maxValue = opts.maxValue || 100; self._getValueFn = opts.getValueFn; self._getMaxFn = opts.getMaxFn; self._color = opts.color || 0x00ff00; self._bar.tint = self._color; if (opts.width) { self._width = opts.width; self._bg.scaleX = self._width / 40; self._bar.scaleX = (self._width - 4) / 40; } if (opts.height) { self._height = opts.height; self._bg.scaleY = self._height / 40; self._bar.scaleY = (self._height - 4) / 40; } }; self.update = function () { var value = self._getValueFn ? self._getValueFn() : self._maxValue; var maxValue = self._getMaxFn ? self._getMaxFn() : self._maxValue; var ratio = Math.max(0, Math.min(1, value / maxValue)); // Color: green > yellow > red if (ratio > 0.6) { self._bar.tint = 0x00ff00; } else if (ratio > 0.3) { self._bar.tint = 0xffff00; } else { self._bar.tint = 0xff0000; } self._bar.scaleX = (self._width - 4) * ratio / 40; }; return self; }); var NPC = Container.expand(function () { var self = Container.call(this); var npcGraphics = self.attachAsset('npc', { anchorX: 0.5, anchorY: 0.5 }); self.isAI = true; // AI-driven self.baseY = 0; self.moveSpeed = 1 + Math.random() * 2; self.moveAngle = Math.random() * Math.PI * 2; self.wanderTimer = 0; self.lastAIAction = 0; self.targetX = null; self.targetY = null; self.rpgName = "NPC-" + Math.floor(Math.random() * 10000); // --- NPC Level System --- // Level range: wave 1 => 1-3, wave 2 => 3-5, wave 3 => 5-7, etc. var minLevel = 1 + (typeof waveNumber !== "undefined" ? waveNumber : 0) * 2; var maxLevel = minLevel + 2; self.level = minLevel + Math.floor(Math.random() * (maxLevel - minLevel + 1)); self.health = 100 + (self.level - 1) * 10; // --- Level Text --- self._levelText = new Text2("Lv." + self.level, { size: 22, fill: 0xcccccc, align: "center" }); self._levelText.anchor.set(0.5, 0); self._levelText.x = 0; self._levelText.y = 40; // Under the NPC sprite self.addChild(self._levelText); // Only floating AI logic, no quests/events/trade // Add dummy interact method to prevent TypeError self.interact = function () { // No interaction for basic NPCs, return empty string return ""; }; self.update = function () { // Update level text position in case of movement if (self._levelText) { self._levelText.x = 0; self._levelText.y = npcGraphics.height / 2 + 4; self._levelText.setText("Lv." + self.level); } // Pause logic: If pauseUntil is set and not expired, skip movement if (self.pauseUntil && LK.ticks < self.pauseUntil) { // Still paused, only float animation self.y += Math.sin(LK.ticks * 0.05) * 0.5; return; } // AI: Sometimes move toward a random point, sometimes wander self.wanderTimer++; if (self.wanderTimer > 120 + Math.random() * 120) { if (Math.random() < 0.5) { // Pick a random point to move toward (simulate AI goal seeking) self.targetX = self.x + (Math.random() - 0.5) * 800; self.targetY = self.y + (Math.random() - 0.5) * 800; } else { self.targetX = null; self.targetY = null; } self.moveAngle = Math.random() * Math.PI * 2; self.wanderTimer = 0; } // Move toward target if set, else wander if (self.targetX !== null && self.targetY !== null) { var dx = self.targetX - self.x; var dy = self.targetY - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 10) { self.x += dx / dist * self.moveSpeed; self.y += dy / dist * self.moveSpeed; self.moveAngle = Math.atan2(dy, dx); } else { self.targetX = null; self.targetY = null; } } else { self.x += Math.cos(self.moveAngle) * self.moveSpeed; self.y += Math.sin(self.moveAngle) * self.moveSpeed; } // Float animation on top of movement self.y += Math.sin(LK.ticks * 0.05) * 0.5; }; return self; }); var Pirate = Container.expand(function () { var self = Container.call(this); var pirateGraphics = self.attachAsset('pirate', { anchorX: 0.5, anchorY: 0.5 }); // --- Pirate Level & Scaling --- self.level = typeof waveNumber !== "undefined" ? 1 + waveNumber : 1; self.health = 30 + (self.level - 1) * 10; self.speed = 2 + Math.floor((self.level - 1) / 10) * 0.2; // Slight speed up every 10 waves self.fireRate = 60 - Math.min((self.level - 1) * 2, 30); // Faster fire at higher levels self.lastFire = 0; self.loot = Math.floor(Math.random() * 30) + 10 + (self.level - 1) * 2; self.moveAngle = Math.random() * Math.PI * 2; self.patrolTimer = 0; self.aggroRange = 600; // Korsan saldırı ve savunma gücü seviyeye göre orantılı artar self.damage = 5 + Math.floor((self.level - 1) * 1.5); // Saldırı gücü daha hızlı artar self.defense = 2 + Math.floor((self.level - 1) * 1.2); // Savunma gücü de seviyeye göre artar // --- Level Text --- self._levelText = new Text2("Lv." + self.level, { size: 22, fill: 0xcccccc, align: "center" }); self._levelText.anchor.set(0.5, 0); self._levelText.x = 0; self._levelText.y = 40; // Under the pirate sprite self.addChild(self._levelText); // Level text only, defense text removed self.takeDamage = function (amount) { self.health -= amount; LK.effects.flashObject(self, 0xffffff, 100); }; self.update = function () { // Update level text position in case of movement if (self._levelText) { self._levelText.x = 0; self._levelText.y = pirateGraphics.height / 2 + 4; self._levelText.setText("Lv." + self.level); } // Defense text removed // Movement AI self.patrolTimer++; if (self.patrolTimer > 180) { self.moveAngle = Math.random() * Math.PI * 2; self.patrolTimer = 0; } // Patrol movement if (self._squadTargetNPC && self._squadTargetNPC.questType === 'defend' && self._squadTargetNPC.questActive) { // Korsan, NPC'yi hedefle var target = self._squadTargetNPC; // Eğer defend quest'te yardım kabul edildiyse, oyuncuya da saldırabilir if (target._defendHelpAccepted === true && Math.random() < 0.5) { // %50 ihtimalle oyuncuya saldır target = Math.random() < 0.5 ? self._squadTargetNPC : ship; } var dx = target.x - self.x; var dy = target.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 10) { self.x += dx / dist * self.speed; self.y += dy / dist * self.speed; self.moveAngle = Math.atan2(dy, dx); } // Ateş et if (LK.ticks - self.lastFire > self.fireRate) { var bullet = new EnemyBullet(); bullet.x = self.x; bullet.y = self.y; var angle = Math.atan2(target.y - self.y, target.x - self.x); bullet.directionX = Math.cos(angle); bullet.directionY = Math.sin(angle); bullet.rotation = angle + Math.PI / 2; enemyBullets.push(bullet); if (game && game.addChild) game.addChild(bullet); self.lastFire = LK.ticks; } } else { self.x += Math.cos(self.moveAngle) * self.speed * 0.5; self.y += Math.sin(self.moveAngle) * self.speed * 0.5; } }; return self; }); // Pirate Base Class var PirateBase = Container.expand(function () { var self = Container.call(this); var baseGraphics = self.attachAsset('pirate', { anchorX: 0.5, anchorY: 0.5, tint: 0x990000, scaleX: 3, scaleY: 3 }); self.health = 300; self.maxHealth = 300; self.attackPower = 10; self.defensePower = 10; self.spawnRadius = 350; self.pirates = []; self.lastPirateSpawn = 0; self.maxPirates = 10; self._destroyed = false; // Health bar self._healthBar = new HealthBar(); self._healthBar.set({ maxValue: function maxValue() { return self.maxHealth; }, getValueFn: function getValueFn() { return self.health; }, getMaxFn: function getMaxFn() { return self.maxHealth; }, width: 120, height: 16, color: 0xff0000 }); self._healthBar.y = -120; self.addChild(self._healthBar); self.takeDamage = function (amount) { self.health -= amount; LK.effects.flashObject(self, 0xff0000, 120); if (self.health <= 0 && !self._destroyed) { self.health = 0; self._destroyed = true; // Remove all pirates around base for (var i = 0; i < self.pirates.length; i++) { if (self.pirates[i] && !self.pirates[i]._destroyed) { self.pirates[i].destroy(); } } // Explosion effect createExplosion(self.x, self.y); // Floating label var label = new Text2("Korsan Üssü Yok Edildi!", { size: 48, fill: 0xffcc00, align: "center" }); label.anchor.set(0.5, 0.5); label.x = self.x; label.y = self.y - 180; if (game && game.addChild) game.addChild(label); self._destroyed = true; self.destroy(); } }; self.update = function () { // Health bar update if (self._healthBar && self._healthBar.update) self._healthBar.update(); // Remove dead pirates from list for (var i = self.pirates.length - 1; i >= 0; i--) { if (!self.pirates[i] || self.pirates[i]._destroyed) { self.pirates.splice(i, 1); } } // Spawn pirates if less than max if (!self._destroyed && self.pirates.length < self.maxPirates && LK.ticks - self.lastPirateSpawn > 90) { var pirate = new Pirate(); var angle = Math.random() * Math.PI * 2; pirate.x = self.x + Math.cos(angle) * (self.spawnRadius + Math.random() * 60); pirate.y = self.y + Math.sin(angle) * (self.spawnRadius + Math.random() * 60); pirate.health = 30 + self.attackPower * 2; pirate.damage = 5 + self.attackPower; pirate.rpgName = "BaseKorsan-" + Math.floor(Math.random() * 10000); pirate._baseRef = self; // Add health bar to pirate pirate._healthBar = new HealthBar(); pirate._healthBar.set({ maxValue: function maxValue() { return pirate.health > 0 ? pirate.health : 0; }, getValueFn: function getValueFn() { return pirate.health > 0 ? pirate.health : 0; }, getMaxFn: function getMaxFn() { return 30 + self.attackPower * 2; }, width: 60, height: 10 }); pirate._healthBar.y = -60; pirate.addChild(pirate._healthBar); pirates.push(pirate); self.pirates.push(pirate); if (game && game.addChild) game.addChild(pirate); self.lastPirateSpawn = LK.ticks; } // Base defense: shoot at player if close var distToShip = Math.sqrt(Math.pow(ship.x - self.x, 2) + Math.pow(ship.y - self.y, 2)); if (!self._destroyed && distToShip < self.spawnRadius + 80 && LK.ticks % 30 === 0) { var bullet = new EnemyBullet(); bullet.x = self.x; bullet.y = self.y; var angle = Math.atan2(ship.y - self.y, ship.x - self.x); bullet.directionX = Math.cos(angle); bullet.directionY = Math.sin(angle); bullet.rotation = angle + Math.PI / 2; bullet.damage = 10 + self.attackPower; enemyBullets.push(bullet); if (game && game.addChild) game.addChild(bullet); } }; return self; }); var Resource = Container.expand(function () { var self = Container.call(this); var resourceGraphics = self.attachAsset('resource', { anchorX: 0.5, anchorY: 0.5 }); // 10 farklı hammadde tipi var resourceTypes = ['metal', 'energy', 'crystal', 'gas', 'ice', 'uranium', 'silicon', 'carbon', 'plasma', 'antimatter']; // --- Değerli hammaddelerin daha az çıkmasını sağlamak için ağırlıklı seçim --- // Market kaldırıldı, sabit fiyatlar kullanılıyor var prices = [100, 80, 120, 90, 70, 200, 110, 60, 150, 300]; // Her hammaddenin ağırlığı: 1 / (fiyat^0.7) ile ters orantılı (daha değerli = daha az) // 0.7 üssüyle daha yumuşak bir dağılım, istenirse 1.0 yapılabilir var weights = []; var totalWeight = 0; for (var i = 0; i < prices.length; i++) { var w = 1 / Math.pow(prices[i], 0.7); weights.push(w); totalWeight += w; } // Rastgele ağırlıklı seçim var r = Math.random() * totalWeight; var acc = 0, idx = 0; for (var i = 0; i < weights.length; i++) { acc += weights[i]; if (r <= acc) { idx = i; break; } } self.type = resourceTypes[idx]; // Miktar: Değerli hammaddelerde miktar da az olsun // maxAmount = 1 + 4 * (ucuzluk ağırlığı) var maxAmount = Math.max(1, Math.round(1 + 4 * (weights[idx] / totalWeight * prices.length))); self.amount = Math.floor(Math.random() * maxAmount) + 1; self.update = function () { self.rotation += 0.03; }; return self; }); var Ship = Container.expand(function () { var self = Container.call(this); var shipGraphics = self.attachAsset('ship', { anchorX: 0.5, anchorY: 0.5 }); self.health = 100; self.maxHealth = 100; self.shield = 50; self.maxShield = 50; self.shieldRegenDelay = 0; self.speed = 5; self.fireRate = 10; self.damage = 10; self.lastFire = 0; self.takeDamage = function (amount) { // Shield absorbs damage first if (self.shield > 0) { var shieldDamage = Math.min(amount, self.shield); self.shield -= shieldDamage; amount -= shieldDamage; LK.effects.flashObject(self, 0x0088ff, 100); self.shieldRegenDelay = 180; // 3 seconds delay before shield regen } if (amount > 0) { self.health -= amount; LK.effects.flashObject(self, 0xff0000, 200); } if (self.health <= 0) { self.health = 0; // --- NO GAME OVER: Respawn with 50% coin/resource loss --- // 1. Lose 50% coins var lostCoins = Math.floor(playerCoins * 0.5); playerCoins = Math.max(0, playerCoins - lostCoins); // 2. Lose 50% of each resource for (var i = 0; i < playerResources.length; i++) { playerResources[i] = Math.floor(playerResources[i] * 0.5); } // 3. Show floating label for penalty var penaltyLabel = new Text2("-" + lostCoins + " coin\nHammadde ve coin kaybı! Yeniden doğdun.", { size: 48, fill: 0xff4444, align: "center" }); penaltyLabel.anchor.set(0.5, 0.5); penaltyLabel.x = self.x; penaltyLabel.y = self.y - 120; if (typeof game !== "undefined" && game.addChild) game.addChild(penaltyLabel); LK.setTimeout(function () { if (penaltyLabel.parent) penaltyLabel.parent.removeChild(penaltyLabel); }, 1800); // 4. Respawn ship at a random safe location (not too close to pirates) var safe = false, tries = 0, newX, newY; while (!safe && tries < 20) { var angle = Math.random() * Math.PI * 2; var dist = 800 + Math.random() * 1200; newX = self.x + Math.cos(angle) * dist; newY = self.y + Math.sin(angle) * dist; safe = true; for (var i = 0; i < pirates.length; i++) { var pdist = Math.sqrt(Math.pow(pirates[i].x - newX, 2) + Math.pow(pirates[i].y - newY, 2)); if (pdist < 400) { safe = false; break; } } tries++; } self.x = newX; self.y = newY; // 5. Restore health and shield self.health = self.maxHealth; self.shield = self.maxShield; self.shieldRegenDelay = 180; // 6. Update UI and save progress if (typeof updateUI === "function") updateUI(); if (typeof saveProgress === "function") saveProgress(); } }; self.update = function () { // Shield regeneration if (self.shieldRegenDelay > 0) { self.shieldRegenDelay--; } else if (self.shield < self.maxShield) { self.shield = Math.min(self.shield + 0.1, self.maxShield); } }; return self; }); var Star = Container.expand(function () { var self = Container.call(this); var starGraphics = self.attachAsset('star', { anchorX: 0.5, anchorY: 0.5 }); self.speed = Math.random() * 2 + 0.5; starGraphics.alpha = Math.random() * 0.8 + 0.2; self.vx = (Math.random() - 0.5) * 0.5; self.vy = (Math.random() - 0.5) * 0.5; self.update = function () { // Slow floating movement self.x += self.vx; self.y += self.vy; }; return self; }); // Suçlu (Criminal) Class - 10x stronger and 10x more rewarding than Pirate var Suclu = Container.expand(function () { var self = Container.call(this); // Use 'alien' asset for visual distinction (could be replaced with a unique asset if available) var sucluGraphics = self.attachAsset('alien', { anchorX: 0.5, anchorY: 0.5, tint: 0xff00ff, // Magenta for visual difference scaleX: 1.2, scaleY: 1.2 }); // --- Suçlu Level & Scaling --- self.level = typeof waveNumber !== "undefined" ? 1 + waveNumber : 1; self.health = 300 + (self.level - 1) * 100; // 10x Pirate health self.speed = 2.5 + Math.floor((self.level - 1) / 10) * 0.2; self.fireRate = 40 - Math.min((self.level - 1) * 2, 20); // Faster fire self.lastFire = 0; self.loot = (Math.floor(Math.random() * 30) + 10 + (self.level - 1) * 2) * 10; // 10x Pirate loot self.moveAngle = Math.random() * Math.PI * 2; self.patrolTimer = 0; self.aggroRange = 700; self.damage = (5 + Math.floor((self.level - 1) * 1.5)) * 10; // 10x Pirate damage self.defense = (2 + Math.floor((self.level - 1) * 1.2)) * 10; // 10x Pirate defense // --- Level Text --- self._levelText = new Text2("Lv." + self.level, { size: 28, fill: 0xff00ff, align: "center" }); self._levelText.anchor.set(0.5, 0); self._levelText.x = 0; self._levelText.y = 50; self.addChild(self._levelText); // Health bar self._healthBar = new HealthBar(); self._healthBar.set({ maxValue: function maxValue() { return self.health > 0 ? self.health : 0; }, getValueFn: function getValueFn() { return self.health > 0 ? self.health : 0; }, getMaxFn: function getMaxFn() { return 300 + (self.level - 1) * 100; }, width: 80, height: 14, color: 0xff00ff }); self._healthBar.y = -70; self.addChild(self._healthBar); self.takeDamage = function (amount) { self.health -= amount; LK.effects.flashObject(self, 0xffffff, 100); }; self.update = function () { // Update level text position if (self._levelText) { self._levelText.x = 0; self._levelText.y = sucluGraphics.height / 2 + 8; self._levelText.setText("Lv." + self.level); } if (self._healthBar && self._healthBar.update) self._healthBar.update(); // Movement AI (similar to Pirate, but more aggressive) self.patrolTimer++; if (self.patrolTimer > 120) { self.moveAngle = Math.random() * Math.PI * 2; self.patrolTimer = 0; } // Find nearest target (NPC or player) var nearestTarget = null; var minDist = Infinity; for (var n = 0; n < npcs.length; n++) { var npc = npcs[n]; var distToNPC = Math.sqrt(Math.pow(npc.x - self.x, 2) + Math.pow(npc.y - self.y, 2)); if (distToNPC < minDist) { minDist = distToNPC; nearestTarget = npc; } } var distToPlayer = Math.sqrt(Math.pow(ship.x - self.x, 2) + Math.pow(ship.y - self.y, 2)); if (distToPlayer < minDist) { minDist = distToPlayer; nearestTarget = ship; } // If there is a target, move and attack if (nearestTarget && minDist < self.aggroRange) { var targetRadius = 50; if (nearestTarget._healthBar && nearestTarget._healthBar._width) { targetRadius = Math.max(targetRadius, nearestTarget._healthBar._width / 2); } var selfRadius = 45; if (self._healthBar && self._healthBar._width) { selfRadius = Math.max(selfRadius, self._healthBar._width / 2); } var minBuffer = (minDist + selfRadius + targetRadius) * 0.05; var minAllowedDist = selfRadius + targetRadius + minBuffer; var angle = Math.atan2(nearestTarget.y - self.y, nearestTarget.x - self.x); if (minDist > minAllowedDist) { var moveDist = Math.min(self.speed, minDist - minAllowedDist); self.x += Math.cos(angle) * moveDist; self.y += Math.sin(angle) * moveDist; self.rotation = angle + Math.PI / 2; } else { self.rotation = angle + Math.PI / 2; } // Shoot at target if (LK.ticks - self.lastFire > self.fireRate) { var bullet = new EnemyBullet(); bullet.x = self.x; bullet.y = self.y; bullet.directionX = Math.cos(angle); bullet.directionY = Math.sin(angle); bullet.rotation = angle + Math.PI / 2; bullet.damage = self.damage; bullet._sucluBullet = true; enemyBullets.push(bullet); if (game && game.addChild) game.addChild(bullet); self.lastFire = LK.ticks; } } else { // Wander randomly self.x += Math.cos(self.moveAngle) * self.speed * 0.5; self.y += Math.sin(self.moveAngle) * self.speed * 0.5; } }; return self; }); // Trade Station Class var TradeStation = Container.expand(function () { var self = Container.call(this); var tradeGraphics = self.attachAsset('npc', { anchorX: 0.5, anchorY: 0.5, tint: 0x00ff99, scaleX: 2, scaleY: 2 }); self.type = 'trade'; self.rotationSpeed = 0.01; self.offerType = Math.random() < 0.5 ? 'buy' : 'sell'; // buy: station buys from player, sell: station sells to player self.resourceType = Math.random() < 0.5 ? 'metal' : 'energy'; self.amount = Math.floor(Math.random() * 10) + 5; self.price = Math.floor(Math.random() * 30) + 10; self.specialOffer = Math.random() < 0.2; // 20% chance for special upgrade offer self.specialUpgrade = null; if (self.specialOffer) { var upgrades = [{ name: 'maxHealth', label: 'Max Health +30', cost: 200 }, { name: 'maxShield', label: 'Max Shield +20', cost: 180 }, { name: 'damage', label: 'Damage +5', cost: 150 }, { name: 'speed', label: 'Speed +1', cost: 120 }]; self.specialUpgrade = upgrades[Math.floor(Math.random() * upgrades.length)]; } self.update = function () { self.rotation += self.rotationSpeed; // Pulse effect var scale = 2 + Math.sin(LK.ticks * 0.05) * 0.1; tradeGraphics.scaleX = scale; tradeGraphics.scaleY = scale; }; return self; }); var UpgradeStation = Container.expand(function () { var self = Container.call(this); var stationGraphics = self.attachAsset('pirate', { anchorX: 0.5, anchorY: 0.5, tint: 0x00ffff, scaleX: 1.5, scaleY: 1.5 }); self.type = 'upgrade'; self.upgrades = [{ name: 'health', cost: 100, metalCost: 10 }, { name: 'shield', cost: 150, metalCost: 15 }, { name: 'damage', cost: 200, energyCost: 20 }, { name: 'speed', cost: 120, energyCost: 10 }]; self.currentUpgrade = 0; self.rotationSpeed = 0.01; self.update = function () { self.rotation += self.rotationSpeed; // Pulse effect var scale = 1.5 + Math.sin(LK.ticks * 0.05) * 0.1; stationGraphics.scaleX = scale; stationGraphics.scaleY = scale; }; return self; }); // Wormhole Teleporter Class var Wormhole = Container.expand(function () { var self = Container.call(this); var whGraphics = self.attachAsset('star', { anchorX: 0.5, anchorY: 0.5, scaleX: 5, scaleY: 5, tint: 0x00ffff }); self.radius = 120; self.cooldown = 0; self.update = function () { whGraphics.rotation += 0.07; // Teleport ship if close and not on cooldown var dx = ship.x - self.x; var dy = ship.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < self.radius && self.cooldown <= 0) { // Teleport ship to a random far location var tx = ship.x + (Math.random() - 0.5) * 4000; var ty = ship.y + (Math.random() - 0.5) * 4000; var dx2 = tx - ship.x; var dy2 = ty - ship.y; ship.x = tx; ship.y = ty; // Move all objects to keep camera effect for (var i = 0; i < stars.length; i++) { stars[i].x -= dx2; stars[i].y -= dy2; } for (var i = 0; i < npcs.length; i++) { npcs[i].x -= dx2; npcs[i].y -= dy2; } for (var i = 0; i < pirates.length; i++) { pirates[i].x -= dx2; pirates[i].y -= dy2; } for (var i = 0; i < coins.length; i++) { coins[i].x -= dx2; coins[i].y -= dy2; } for (var i = 0; i < resources.length; i++) { resources[i].x -= dx2; resources[i].y -= dy2; } for (var i = 0; i < bullets.length; i++) { bullets[i].x -= dx2; bullets[i].y -= dy2; } for (var i = 0; i < enemyBullets.length; i++) { enemyBullets[i].x -= dx2; enemyBullets[i].y -= dy2; } for (var i = 0; i < asteroids.length; i++) { asteroids[i].x -= dx2; asteroids[i].y -= dy2; } for (var i = 0; i < upgradeStations.length; i++) { upgradeStations[i].x -= dx2; upgradeStations[i].y -= dy2; } // boostParticles removed (no boost system) for (var i = 0; i < explosions.length; i++) { explosions[i].x -= dx2; explosions[i].y -= dy2; } for (var i = 0; i < blackHoles.length; i++) { blackHoles[i].x -= dx2; blackHoles[i].y -= dy2; } for (var i = 0; i < wormholes.length; i++) { if (wormholes[i] !== self) { wormholes[i].x -= dx2; wormholes[i].y -= dy2; } } self.cooldown = 180; LK.effects.flashScreen(0x00ffff, 500); } if (self.cooldown > 0) self.cooldown--; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000033 }); /**** * Game Code ****/ // (No other LK.showGameOver() in Game Code section) var ship; var joystickBase; var joystickHandle; var isDragging = false; var bullets = []; var enemyBullets = []; var npcs = []; var pirates = []; var suclus = []; var coins = []; var resources = []; var stars = []; var asteroids = []; var upgradeStations = []; var explosions = []; var blackHoles = []; var wormholes = []; var tradeStations = []; var pirateBases = []; var tradeText = null; // No trade text needed // Helper: spawn a pirate base at a random edge, with pirates around it function spawnPirateBase() { var base = new PirateBase(); // Spawn from edges of visible area var edge = Math.floor(Math.random() * 4); switch (edge) { case 0: // Top base.x = ship.x + (Math.random() - 0.5) * 2000; base.y = ship.y - 1600; break; case 1: // Right base.x = ship.x + 1600; base.y = ship.y + (Math.random() - 0.5) * 2000; break; case 2: // Bottom base.x = ship.x + (Math.random() - 0.5) * 2000; base.y = ship.y + 1600; break; case 3: // Left base.x = ship.x - 1600; base.y = ship.y + (Math.random() - 0.5) * 2000; break; // --- MINI MAP OVERLAY DRAW/UPDATE --- if (window._miniMapVisible) { // Helper to convert world to mini map var toMiniMap = function toMiniMap(wx, wy) { return { x: mapCenterX + (wx - ship.x) * mapScale, y: mapCenterY + (wy - ship.y) * mapScale }; }; // Draw ship // Create container if not exists if (!window._miniMapContainer) { var miniMapContainer = new Container(); // Position: below the ship, centered horizontally // Ship is at (ship.x, ship.y) in world, but we want minimap in screen coordinates // Center horizontally, and place just below the ship (ship.y + ship height/2 + margin) var mapSize = 480; var marginBelowShip = 80; var screenW = 2048, screenH = 2732; var miniMapX = (screenW - mapSize) / 2; var miniMapY = Math.min(screenH - mapSize - 40, Math.max(0, ship.y + 100 + marginBelowShip - mapSize / 2)); // Clamp to screen miniMapY = Math.max(200, Math.min(screenH - mapSize - 40, miniMapY)); miniMapContainer.x = miniMapX; miniMapContainer.y = miniMapY; window._miniMapContainer = miniMapContainer; game.addChild(miniMapContainer); } var miniMapContainer = window._miniMapContainer; // Remove previous elements for (var i = 0; i < window._miniMapElements.length; i++) { if (window._miniMapElements[i] && window._miniMapElements[i].parent) { window._miniMapElements[i].parent.removeChild(window._miniMapElements[i]); } } window._miniMapElements = []; // Draw background var bg = LK.getAsset('resource', { anchorX: 0, anchorY: 0, x: 0, y: 0, scaleX: 12, scaleY: 12, tint: 0x111133, alpha: 0.92 }); miniMapContainer.addChild(bg); window._miniMapElements.push(bg); // Draw border var border = LK.getAsset('resource', { anchorX: 0, anchorY: 0, x: 0, y: 0, scaleX: 12, scaleY: 12, tint: 0x00ccff, alpha: 0.25 }); miniMapContainer.addChild(border); window._miniMapElements.push(border); // Mini map covers 6000x6000 px area centered on ship var mapSize = 480; var worldSize = 6000; var halfWorld = worldSize / 2; var mapScale = mapSize / worldSize; var mapCenterX = mapSize / 2; var mapCenterY = mapSize / 2; var shipPos = toMiniMap(ship.x, ship.y); var shipDot = LK.getAsset('ship', { anchorX: 0.5, anchorY: 0.5, x: shipPos.x, y: shipPos.y, scaleX: 0.3, scaleY: 0.3, tint: 0x00ff00, alpha: 1 }); miniMapContainer.addChild(shipDot); window._miniMapElements.push(shipDot); // Draw pirates for (var i = 0; i < pirates.length; i++) { var p = pirates[i]; if (p._destroyed) continue; var pos = toMiniMap(p.x, p.y); var pirateDot = LK.getAsset('pirate', { anchorX: 0.5, anchorY: 0.5, x: pos.x, y: pos.y, scaleX: 0.18, scaleY: 0.18, tint: 0xff4444, alpha: 0.85 }); miniMapContainer.addChild(pirateDot); window._miniMapElements.push(pirateDot); } // Draw NPCs for (var i = 0; i < npcs.length; i++) { var n = npcs[i]; var pos = toMiniMap(n.x, n.y); var npcDot = LK.getAsset('npc', { anchorX: 0.5, anchorY: 0.5, x: pos.x, y: pos.y, scaleX: 0.18, scaleY: 0.18, tint: 0x00ccff, alpha: 0.85 }); miniMapContainer.addChild(npcDot); window._miniMapElements.push(npcDot); // If NPC has active quest target, draw target marker if (n.questActive && n.questTarget) { var tx, ty; if (n.questType === 'hunt' && n.questTarget.x !== undefined && n.questTarget.y !== undefined && !n.questTarget._destroyed) { tx = n.questTarget.x; ty = n.questTarget.y; } else if (n.questTarget.x !== undefined && n.questTarget.y !== undefined) { tx = n.questTarget.x; ty = n.questTarget.y; } if (typeof tx === "number" && typeof ty === "number") { var tpos = toMiniMap(tx, ty); var color = 0xffff00; if (n.questType === 'explore') color = 0x00ffcc; if (n.questType === 'delivery') color = 0xffcc00; if (n.questType === 'escort') color = 0x00ff99; if (n.questType === 'hunt') color = 0xff4444; var targetDot = LK.getAsset('bullet', { anchorX: 0.5, anchorY: 0.5, x: tpos.x, y: tpos.y, scaleX: 0.22, scaleY: 0.22, tint: color, alpha: 0.95 }); miniMapContainer.addChild(targetDot); window._miniMapElements.push(targetDot); // Add label var label = new Text2(n.questType.charAt(0).toUpperCase() + n.questType.slice(1), { size: 18, fill: color, align: "center" }); label.anchor.set(0.5, 0); label.x = tpos.x; label.y = tpos.y + 12; miniMapContainer.addChild(label); window._miniMapElements.push(label); } } } // Draw derelict ship if (window.derelictShip && window.derelictShip.x !== undefined && window.derelictShip.y !== undefined) { var d = window.derelictShip; var dpos = toMiniMap(d.x, d.y); var derelictDot = LK.getAsset('ship', { anchorX: 0.5, anchorY: 0.5, x: dpos.x, y: dpos.y, scaleX: 0.22, scaleY: 0.22, tint: 0xcccccc, alpha: 0.8 }); miniMapContainer.addChild(derelictDot); window._miniMapElements.push(derelictDot); var label = new Text2("Gemi", { size: 16, fill: 0xcccccc, align: "center" }); label.anchor.set(0.5, 0); label.x = dpos.x; label.y = dpos.y + 10; miniMapContainer.addChild(label); window._miniMapElements.push(label); } // Draw distress event if (window.distressEvent && window.distressEvent.x !== undefined && window.distressEvent.y !== undefined) { var e = window.distressEvent; var epos = toMiniMap(e.x, e.y); var distressDot = LK.getAsset('star', { anchorX: 0.5, anchorY: 0.5, x: epos.x, y: epos.y, scaleX: 0.22, scaleY: 0.22, tint: 0xff00ff, alpha: 0.8 }); miniMapContainer.addChild(distressDot); window._miniMapElements.push(distressDot); var label = new Text2("İmdat", { size: 16, fill: 0xff00ff, align: "center" }); label.anchor.set(0.5, 0); label.x = epos.x; label.y = epos.y + 10; miniMapContainer.addChild(label); window._miniMapElements.push(label); } // Draw trade stations for (var i = 0; i < tradeStations.length; i++) { var ts = tradeStations[i]; var tpos = toMiniMap(ts.x, ts.y); var tradeDot = LK.getAsset('npc', { anchorX: 0.5, anchorY: 0.5, x: tpos.x, y: tpos.y, scaleX: 0.16, scaleY: 0.16, tint: 0x00ffcc, alpha: 0.7 }); miniMapContainer.addChild(tradeDot); window._miniMapElements.push(tradeDot); } // Draw upgrade stations for (var i = 0; i < upgradeStations.length; i++) { var us = upgradeStations[i]; var upos = toMiniMap(us.x, us.y); var upgDot = LK.getAsset('pirate', { anchorX: 0.5, anchorY: 0.5, x: upos.x, y: upos.y, scaleX: 0.16, scaleY: 0.16, tint: 0x00ffff, alpha: 0.7 }); miniMapContainer.addChild(upgDot); window._miniMapElements.push(upgDot); } // Draw black holes for (var i = 0; i < blackHoles.length; i++) { var bh = blackHoles[i]; var bhpos = toMiniMap(bh.x, bh.y); var bhDot = LK.getAsset('star', { anchorX: 0.5, anchorY: 0.5, x: bhpos.x, y: bhpos.y, scaleX: 0.18, scaleY: 0.18, tint: 0x222222, alpha: 0.7 }); miniMapContainer.addChild(bhDot); window._miniMapElements.push(bhDot); } // Draw wormholes for (var i = 0; i < wormholes.length; i++) { var wh = wormholes[i]; var whpos = toMiniMap(wh.x, wh.y); var whDot = LK.getAsset('star', { anchorX: 0.5, anchorY: 0.5, x: whpos.x, y: whpos.y, scaleX: 0.18, scaleY: 0.18, tint: 0x00ffff, alpha: 0.7 }); miniMapContainer.addChild(whDot); window._miniMapElements.push(whDot); } // Draw pirate bases for (var i = 0; i < pirateBases.length; i++) { var pb = pirateBases[i]; var pbpos = toMiniMap(pb.x, pb.y); var pbDot = LK.getAsset('pirate', { anchorX: 0.5, anchorY: 0.5, x: pbpos.x, y: pbpos.y, scaleX: 0.22, scaleY: 0.22, tint: 0xff00ff, alpha: 0.8 }); miniMapContainer.addChild(pbDot); window._miniMapElements.push(pbDot); var label = new Text2("Üs", { size: 16, fill: 0xff00ff, align: "center" }); label.anchor.set(0.5, 0); label.x = pbpos.x; label.y = pbpos.y + 10; miniMapContainer.addChild(label); window._miniMapElements.push(label); } // Draw asteroids (only those close to ship) for (var i = 0; i < asteroids.length; i++) { var a = asteroids[i]; var dist = Math.sqrt(Math.pow(a.x - ship.x, 2) + Math.pow(a.y - ship.y, 2)); if (dist > 3000) continue; var apos = toMiniMap(a.x, a.y); var aDot = LK.getAsset('resource', { anchorX: 0.5, anchorY: 0.5, x: apos.x, y: apos.y, scaleX: 0.12, scaleY: 0.12, tint: 0x8B4513, alpha: 0.6 }); miniMapContainer.addChild(aDot); window._miniMapElements.push(aDot); } // Draw label var title = new Text2("Mini Map", { size: 32, fill: 0xffffff, align: "center" }); title.anchor.set(0.5, 0); title.x = mapSize / 2; title.y = 10; miniMapContainer.addChild(title); window._miniMapElements.push(title); // Draw close hint var hint = new Text2("Kapatmak için tekrar dokun", { size: 18, fill: 0xcccccc, align: "center" }); hint.anchor.set(0.5, 1); hint.x = mapSize / 2; hint.y = mapSize - 10; miniMapContainer.addChild(hint); window._miniMapElements.push(hint); } else if (window._miniMapContainer && window._miniMapContainer.parent) { window._miniMapContainer.parent.removeChild(window._miniMapContainer); window._miniMapElements = []; window._miniMapContainer = null; } } ; pirateBases.push(base); game.addChild(base); // Spawn initial pirates around base for (var i = 0; i < 10; i++) { var pirate = new Pirate(); var angle = Math.PI * 2 * (i / 10); pirate.x = base.x + Math.cos(angle) * (base.spawnRadius + Math.random() * 60); pirate.y = base.y + Math.sin(angle) * (base.spawnRadius + Math.random() * 60); // Level range: wave 1 => 1-3, wave 2 => 3-5, wave 3 => 5-7, etc. var minLevel = 1 + waveNumber * 2; var maxLevel = minLevel + 2; pirate.level = minLevel + Math.floor(Math.random() * (maxLevel - minLevel + 1)); pirate.health = 30 + (pirate.level - 1) * 10 + base.attackPower * 2; pirate.damage = 5 + Math.floor((pirate.level - 1) * 1.5) + base.attackPower; pirate.defense = 2 + Math.floor((pirate.level - 1) * 1.2) + base.defensePower; pirate.rpgName = "BaseKorsan-" + Math.floor(Math.random() * 10000); pirate._baseRef = base; // Add health bar to pirate pirate._healthBar = new HealthBar(); pirate._healthBar.set({ maxValue: function maxValue() { return pirate.health > 0 ? pirate.health : 0; }, getValueFn: function getValueFn() { return pirate.health > 0 ? pirate.health : 0; }, getMaxFn: function getMaxFn() { return 30 + base.attackPower * 2; }, width: 60, height: 10 }); pirate._healthBar.y = -60; pirate.addChild(pirate._healthBar); pirates.push(pirate); base.pirates.push(pirate); game.addChild(pirate); } } // tradeText UI removed (no tradeText in this version) var camera = { x: 0, y: 0 }; // --- Helper for multi-pirate attack quest --- function spawnPirateSquad(centerX, centerY, count, targetNPC) { var squad = []; for (var i = 0; i < count; i++) { var pirate = new Pirate(); var angle = Math.PI * 2 * (i / count); pirate.x = centerX + Math.cos(angle) * 200 + (Math.random() - 0.5) * 60; pirate.y = centerY + Math.sin(angle) * 200 + (Math.random() - 0.5) * 60; // Level range: wave 1 => 1-3, wave 2 => 3-5, wave 3 => 5-7, etc. var minLevel = 1 + waveNumber * 2; var maxLevel = minLevel + 2; pirate.level = minLevel + Math.floor(Math.random() * (maxLevel - minLevel + 1)); pirate.health = 30 + (pirate.level - 1) * 10; pirate.damage = 5 + Math.floor((pirate.level - 1) * 1.5); pirate.defense = 2 + Math.floor((pirate.level - 1) * 1.2); pirate.rpgName = "Korsan-" + Math.floor(Math.random() * 10000); pirate._squadTargetNPC = targetNPC; pirates.push(pirate); game.addChild(pirate); squad.push(pirate); } return squad; } // Trade station tap detection (RPG/ticaret) for (var i = 0; i < tradeStations.length; i++) { var ts = tradeStations[i]; var dist = Math.sqrt(Math.pow(ts.x - ship.x, 2) + Math.pow(ts.y - ship.y, 2)); if (dist < 180) { game._lastTradeStationTap = LK.ticks; break; } } var waveNumber = 0; var enemiesKilled = 0; var totalDistance = 0; // Player stats var playerCoins = storage.coins || 0; // 10 hammadde için oyuncu envanteri var playerResources = [storage.metal || 0, // metal storage.energy || 0, // energy storage.crystal || 0, // crystal storage.gas || 0, // gas storage.ice || 0, // ice storage.uranium || 0, // uranium storage.silicon || 0, // silicon storage.carbon || 0, // carbon storage.plasma || 0, // plasma storage.antimatter || 0 // antimatter ]; // Aliases for compatibility with old code var playerMetal = playerResources[0]; var playerEnergy = playerResources[1]; var questsCompleted = storage.questsCompleted || 0; // --- Player Level/EXP --- var playerLevel = typeof storage.playerLevel !== "undefined" ? storage.playerLevel : 1; var playerEXP = typeof storage.playerEXP !== "undefined" ? storage.playerEXP : 0; function expToNext(level) { // Simple EXP curve: next = 10 + 5*(level-1) return 10 + 5 * (level - 1); } // UI Elements // Calculate the unified font size (30% smaller than expText, then %10 büyüt) var unifiedFontSize = Math.round(38 * 0.7 * 1.1); var coinText = new Text2('Coins: ' + playerCoins, { size: unifiedFontSize, fill: 0xFFFF00 }); coinText.anchor.set(0, 0); coinText.x = 120; coinText.y = 20; LK.gui.topLeft.addChild(coinText); // --- NPC ile savaş butonu --- var npcFightBtnFont = Math.round(unifiedFontSize * 1.1); window.npcFightBtn = new Text2("NPC ile Savaş", { size: npcFightBtnFont, fill: 0xff4444, align: "center" }); window.npcFightBtn.anchor.set(0.5, 0.5); // Place at bottom center, above the bottom edge window.npcFightBtn.x = 2048 / 2; window.npcFightBtn.y = 2732 - 300; // moved 2 lines (about 120px) higher LK.gui.bottom.addChild(window.npcFightBtn); window.npcFightMode = false; // --- UZAY İSTASYONU TESLİMAT BUTTON (above Reset, 2 rows up) --- if (!window.stationDeliveryBtn) { var deliveryBtnFont = Math.round(unifiedFontSize * 1.1); window.stationDeliveryBtn = new Text2("", { size: deliveryBtnFont, fill: 0x00ffcc, align: "center" }); window.stationDeliveryBtn.anchor.set(1, 1); // Place 2 rows above Reset (row = 80px) window.stationDeliveryBtn.x = -40; window.stationDeliveryBtn.y = -40 - 2 * 90; // Add image above the button, 10% higher (yukarıya %10) if (!window.stationDeliveryBtnImage) { // Use the special image for the transparent button area var imgAsset = LK.getAsset('stationDeliveryBtnAreaImg', { anchorX: 1, anchorY: 1, scaleX: 0.7, scaleY: 0.7 }); // Place image at the same x, but y is 10% higher (10% of image height above the button) // Keep the station image fixed (do not move it up) imgAsset.x = window.stationDeliveryBtn.x; imgAsset.y = window.stationDeliveryBtn.y - imgAsset.height * 1.1; window.stationDeliveryBtnImage = imgAsset; LK.gui.bottomRight.addChild(window.stationDeliveryBtnImage); // Add a transparent button area exactly the size and position of the image for İstasyon Teslimat var stationDeliveryBtnArea = new Text2("", { size: 1, fill: 0xffffff, align: "center" }); stationDeliveryBtnArea.anchor.set(1, 1); // Place the button area exactly behind the image, matching its position and size stationDeliveryBtnArea.x = imgAsset.x; // Move the button area 1 row (imgAsset.height) above the image stationDeliveryBtnArea.y = imgAsset.y - imgAsset.height; stationDeliveryBtnArea.width = imgAsset.width; stationDeliveryBtnArea.height = imgAsset.height; stationDeliveryBtnArea.alpha = 0; // fully transparent, but still receives taps window.stationDeliveryBtnArea = stationDeliveryBtnArea; // Add the button area BEFORE the image so it is behind LK.gui.bottomRight.addChild(stationDeliveryBtnArea); LK.gui.bottomRight.addChild(window.stationDeliveryBtnImage); } LK.gui.bottomRight.addChild(window.stationDeliveryBtn); // Add 'İstasyona Hammadde Gönder' text 2 rows below the button if (!window.stationSendResourceText) { var sendTextFont = Math.max(8, Math.round(unifiedFontSize * 1.0) - 2); window.stationSendResourceText = new Text2("", { size: sendTextFont, fill: 0xffffff, align: "center" }); window.stationSendResourceText.anchor.set(1, 1); // 2 rows below the stationDeliveryBtn (row = 90px) window.stationSendResourceText.x = window.stationDeliveryBtn.x; window.stationSendResourceText.y = window.stationDeliveryBtn.y + 1 * 90; LK.gui.bottomRight.addChild(window.stationSendResourceText); } } // --- RESET BUTTON (bottom right) --- if (!game._resetBtn) { game._resetBtn = new Text2("Reset", { size: Math.round(unifiedFontSize * 1.1), fill: 0xff4444, align: "center" }); game._resetBtn.anchor.set(1, 1); // Place at bottom right, with margin from edge game._resetBtn.x = -40; game._resetBtn.y = -40; LK.gui.bottomRight.addChild(game._resetBtn); } // --- UZAY İSTASYONU TESLİMAT PANEL SYSTEM --- // State for delivery system if (!window.stationDeliveryState) { // 10 hammadde için rastgele 50-200 arası istek, bonus %2-5 arası window.stationDeliveryState = { requests: [], delivered: [], completed: false, bonus: 0 }; for (var i = 0; i < 10; i++) { var req = 50 + Math.floor(Math.random() * 151); // 50-200 window.stationDeliveryState.requests.push(req); window.stationDeliveryState.delivered.push(0); } window.stationDeliveryState.bonus = 2 + Math.floor(Math.random() * 4); // 2-5 window.stationDeliveryState.completed = false; window.stationDeliveryState.rewardClaimed = false; } // Helper to open/close panel window.openStationDeliveryPanel = function () { if (window.stationDeliveryPanel) return; // Increase font size by 2 for all panel texts/buttons var panelFontSize = unifiedFontSize + 2; var panelBtnFontSize = panelFontSize; var labelFontSize = panelFontSize; var closeBtnFontSize = panelFontSize; var claimBtnFontSize = panelFontSize; var bonusFontSize = panelFontSize; var infoFontSize = panelFontSize; var titleFontSize = panelFontSize; // Calculate new panel size to fit enlarged text/buttons var rowH = 80 + 8; // add 8px for extra font size var panelW = 900 + 120; // add width for larger text/buttons var panelH = 1100 + 2 * rowH; // add height for larger text/buttons var px = 1024, py = 900; // Panel BG window.stationDeliveryPanelBG = LK.getAsset('resource', { anchorX: 0.5, anchorY: 0.5, x: px, y: py, scaleX: panelW / 40, scaleY: panelH / 40, tint: 0x223355, alpha: 0.97 }); // Title window.stationDeliveryPanelTitle = new Text2("Uzay İstasyonu Teslimat", { size: titleFontSize, fill: 0x00ffcc, align: "center" }); window.stationDeliveryPanelTitle.anchor.set(0.5, 0); window.stationDeliveryPanelTitle.x = px; window.stationDeliveryPanelTitle.y = py - panelH / 2 + 40; // Info text window.stationDeliveryPanelInfoText = new Text2("İstasyonun özel hammadde isteklerini tamamla!\nTümünü teslim edince +" + window.stationDeliveryState.bonus + "% bonus fiyattan satılır.", { size: infoFontSize, fill: 0xffffff, align: "center" }); window.stationDeliveryPanelInfoText.anchor.set(0.5, 0); window.stationDeliveryPanelInfoText.x = px; window.stationDeliveryPanelInfoText.y = window.stationDeliveryPanelTitle.y + 60; // Close button window.stationDeliveryPanelCloseBtn = new Text2("Kapat", { size: unifiedFontSize + 4, // 2 font larger than Coins fill: 0xff4444, align: "center" }); window.stationDeliveryPanelCloseBtn.anchor.set(0.5, 0.5); // Move close button above the panel title, with extra margin window.stationDeliveryPanelCloseBtn.x = px; window.stationDeliveryPanelCloseBtn.y = window.stationDeliveryPanelTitle.y - 110; // further above title // Resource request labels and delivery buttons window.stationDeliveryLabels = []; window.stationDeliveryDeliverBtns = []; // Move all resource rows down by 3% of the panel height var startY = window.stationDeliveryPanelInfoText.y + 80 + Math.round(panelH * 0.03); for (var i = 0; i < window.resourceLabelOrder.length; i++) { var resObj = window.resourceLabelOrder[i]; var req = window.stationDeliveryState.requests[resObj.origIdx]; var delivered = window.stationDeliveryState.delivered[resObj.origIdx]; var label = new Text2(resObj.name + ": " + delivered + " / " + req, { size: labelFontSize, fill: 0xffffff, align: "left" }); label.anchor.set(0, 0.5); label.x = px - panelW / 2 + 60; label.y = startY + i * rowH; window.stationDeliveryLabels.push(label); // Teslim Et button var teslimBtn = new Text2("Teslim Et", { size: panelBtnFontSize, fill: 0x00ff99, align: "center" }); teslimBtn.anchor.set(0.5, 0.5); teslimBtn.x = px + 220; teslimBtn.y = label.y; teslimBtn._stationResIdx = resObj.origIdx; window.stationDeliveryDeliverBtns.push(teslimBtn); } // Bonus info window.stationDeliveryPanelBonusText = new Text2("Tüm istekler tamamlanınca +" + window.stationDeliveryState.bonus + "% bonus fiyattan satılır.", { size: bonusFontSize, fill: 0xffff00, align: "center" }); window.stationDeliveryPanelBonusText.anchor.set(0.5, 0); window.stationDeliveryPanelBonusText.x = px; window.stationDeliveryPanelBonusText.y = startY + rowH * 10 + 30; // Teslimatı Tamamla (ödül al) butonu window.stationDeliveryPanelClaimBtn = new Text2("Tümünü Teslim Et & Ödülü Al", { size: claimBtnFontSize, fill: 0xffcc00, align: "center" }); window.stationDeliveryPanelClaimBtn.anchor.set(0.5, 0.5); window.stationDeliveryPanelClaimBtn.x = px; window.stationDeliveryPanelClaimBtn.y = window.stationDeliveryPanelBonusText.y + 90; // Add to game game.addChild(window.stationDeliveryPanelBG); game.addChild(window.stationDeliveryPanelTitle); game.addChild(window.stationDeliveryPanelInfoText); game.addChild(window.stationDeliveryPanelCloseBtn); for (var i = 0; i < window.stationDeliveryLabels.length; i++) game.addChild(window.stationDeliveryLabels[i]); for (var i = 0; i < window.stationDeliveryDeliverBtns.length; i++) game.addChild(window.stationDeliveryDeliverBtns[i]); game.addChild(window.stationDeliveryPanelBonusText); game.addChild(window.stationDeliveryPanelClaimBtn); window.stationDeliveryPanel = true; }; window.closeStationDeliveryPanel = function () { if (!window.stationDeliveryPanel) return; if (window.stationDeliveryPanelBG && window.stationDeliveryPanelBG.parent) window.stationDeliveryPanelBG.parent.removeChild(window.stationDeliveryPanelBG); if (window.stationDeliveryPanelTitle && window.stationDeliveryPanelTitle.parent) window.stationDeliveryPanelTitle.parent.removeChild(window.stationDeliveryPanelTitle); if (window.stationDeliveryPanelInfoText && window.stationDeliveryPanelInfoText.parent) window.stationDeliveryPanelInfoText.parent.removeChild(window.stationDeliveryPanelInfoText); if (window.stationDeliveryPanelCloseBtn && window.stationDeliveryPanelCloseBtn.parent) window.stationDeliveryPanelCloseBtn.parent.removeChild(window.stationDeliveryPanelCloseBtn); if (window.stationDeliveryLabels) for (var i = 0; i < window.stationDeliveryLabels.length; i++) if (window.stationDeliveryLabels[i] && window.stationDeliveryLabels[i].parent) window.stationDeliveryLabels[i].parent.removeChild(window.stationDeliveryLabels[i]); if (window.stationDeliveryDeliverBtns) for (var i = 0; i < window.stationDeliveryDeliverBtns.length; i++) if (window.stationDeliveryDeliverBtns[i] && window.stationDeliveryDeliverBtns[i].parent) window.stationDeliveryDeliverBtns[i].parent.removeChild(window.stationDeliveryDeliverBtns[i]); if (window.stationDeliveryPanelBonusText && window.stationDeliveryPanelBonusText.parent) window.stationDeliveryPanelBonusText.parent.removeChild(window.stationDeliveryPanelBonusText); if (window.stationDeliveryPanelClaimBtn && window.stationDeliveryPanelClaimBtn.parent) window.stationDeliveryPanelClaimBtn.parent.removeChild(window.stationDeliveryPanelClaimBtn); window.stationDeliveryPanel = null; window.stationDeliveryPanelBG = null; window.stationDeliveryPanelTitle = null; window.stationDeliveryPanelInfoText = null; window.stationDeliveryPanelCloseBtn = null; window.stationDeliveryLabels = null; window.stationDeliveryDeliverBtns = null; window.stationDeliveryPanelBonusText = null; window.stationDeliveryPanelClaimBtn = null; }; // --- GAME TIME LABEL --- // Track game start time in ticks var gameStartTick = LK.ticks; var gameTimeText = new Text2('Game Time: 0:00', { size: unifiedFontSize, fill: 0xcccccc }); gameTimeText.anchor.set(0, 0); gameTimeText.x = coinText.x + coinText.width + 40; gameTimeText.y = coinText.y; LK.gui.topLeft.addChild(gameTimeText); // Add an image below the Game Time label if (!window.gameTimeImage) { // Use an existing image asset, e.g. 'teslimEtBtnBg' as a placeholder // Move the Global Panel image and button to the row above the station image var imgScale = 0.7; var imgAsset = LK.getAsset('teslimEtBtnBg', { anchorX: 1, anchorY: 1, scaleX: imgScale, scaleY: imgScale }); // Place the image at the same x as the stationDeliveryBtnImage, but 1 row above it // If stationDeliveryBtnImage exists, align to it var refImg = window.stationDeliveryBtnImage; if (refImg) { imgAsset.x = refImg.x; imgAsset.y = refImg.y - refImg.height; // 1 row above station image } else { // fallback: 10% right from left edge, and 10px below the Game Time label imgAsset.x = Math.round(2048 * 0.10); imgAsset.y = gameTimeText.y + gameTimeText.height + 10; } window.gameTimeImage = imgAsset; LK.gui.bottomRight.addChild(window.gameTimeImage); // --- Add a new independent image file at the position 2 rows above Hammadde Takası (Resource Trade) image --- // Remove the previously created image if it exists if (window.resourceTradePanelImage && window.resourceTradePanelImage.parent) { window.resourceTradePanelImage.parent.removeChild(window.resourceTradePanelImage); window.resourceTradePanelImage = null; } // Create a new independent image at the same position (now 1 row above Hammadde Takası image) if (!window.resourceTradePanelIndependentImage) { var independentImgScale = 0.7; var independentImgAsset = LK.getAsset('resourceTradePanelIndependentCus', { anchorX: 1, anchorY: 1, scaleX: independentImgScale, scaleY: independentImgScale }); // Place 1 row above the Hammadde Takası (Resource Trade) image independentImgAsset.x = imgAsset.x; independentImgAsset.y = imgAsset.y - imgAsset.height * 1; window.resourceTradePanelIndependentImage = independentImgAsset; LK.gui.bottomRight.addChild(independentImgAsset); // Move the Hammadde Stoğu panel button (tap area) 2 rows above the image, image stays fixed if (!window.resourceTradePanelIndependentBtn) { var btn = new Text2("", { size: 1, fill: 0xffffff, align: "center" }); btn.anchor.set(1, 1); btn.x = independentImgAsset.x; btn.y = independentImgAsset.y - independentImgAsset.height * 2; // 2 rows above the image btn.width = independentImgAsset.width; btn.height = independentImgAsset.height; btn.alpha = 0; // fully transparent, but still receives taps window.resourceTradePanelIndependentBtn = btn; LK.gui.bottomRight.addChild(btn); } } // Add a transparent button area exactly the size and position of the image for Global Market var marketBtn = new Text2("Global Market", { size: 1, fill: 0xffffff, align: "center" }); marketBtn.anchor.set(1, 1); marketBtn.x = imgAsset.x; // Move the button area 2 rows (imgAsset.height * 2) above the image, image stays fixed marketBtn.y = imgAsset.y - imgAsset.height * 2; // Grow the button area 10% downward and shrink it 5% from the top marketBtn.width = imgAsset.width; marketBtn.height = imgAsset.height * 1.10 * 0.95; // first grow 10%, then shrink 5% from top marketBtn.alpha = 0; // fully transparent, but still receives taps window.globalMarketBtn = marketBtn; LK.gui.bottomRight.addChild(marketBtn); } // --- RESOURCE TRADE PANEL STATE --- if (!window.resourceTradePanelState) { // 10 hammadde için değerler (1-10 arası, rastgele başlat) window.resourceTradeValues = []; for (var i = 0; i < 10; i++) { window.resourceTradeValues.push(1 + Math.floor(Math.random() * 10)); } window.resourceTradePanelState = { open: false, lastValueUpdateTick: LK.ticks }; } // Timer: her 5 saniyede bir (300 tick) değerleri değiştir if (!window._resourceTradeValueTimer) { window._resourceTradeValueTimer = LK.setInterval(function () { if (!window.resourceTradeValues) return; for (var i = 0; i < window.resourceTradeValues.length; i++) { // Değeri -3/+3 arası değiştir, 1-10 aralığında tut var delta = Math.floor(Math.random() * 7) - 3; window.resourceTradeValues[i] = Math.max(1, Math.min(10, window.resourceTradeValues[i] + delta)); } // Panel açıksa UI güncelle if (window.resourceTradePanelState && window.resourceTradePanelState.open && typeof window.updateResourceTradePanel === "function") { window.updateResourceTradePanel(); } }, 5000); } // Resource UI: create 10 vertically stacked resource labels, left-aligned // Sort resourceTypes by name length descending, keep original index for mapping to playerResources var resourceTypes = ['Metal', 'Energy', 'Crystal', 'Gas', 'Ice', 'Uranium', 'Silicon', 'Carbon', 'Plasma', 'Antimatter']; var resourceTypeObjs = []; for (var i = 0; i < resourceTypes.length; i++) { resourceTypeObjs.push({ name: resourceTypes[i], origIdx: i }); } resourceTypeObjs.sort(function (a, b) { // Sort by name length descending, then alphabetically for ties if (b.name.length !== a.name.length) return b.name.length - a.name.length; return a.name.localeCompare(b.name); }); window.resourceLabels = []; window.resourceLabelOrder = resourceTypeObjs; // Save for updateUI var resourceIconMargin = 8; var resourceLabelStartY = Math.round(2732 * 0.05); // 5% down from the top for (var i = 0; i < resourceTypeObjs.length; i++) { var label = new Text2(resourceTypeObjs[i].name + ': 0', { size: unifiedFontSize, fill: 0xFFFFFF }); label.anchor.set(0, 0); label.x = 20; // flush to left edge, but leave margin for menu icon label.y = resourceLabelStartY + i * (unifiedFontSize + resourceIconMargin); // Do NOT add to GUI, so resource stock text is hidden on main screen // LK.gui.topLeft.addChild(label); window.resourceLabels.push(label); } // --- RESOURCE TRADE PANEL LOGIC --- window.openResourceTradePanel = function () { if (window.resourceTradePanelState.open) return; window.resourceTradePanelState.open = true; // Increase font size by 2 for all panel texts/buttons var panelFontSize = unifiedFontSize + 2; var panelBtnFontSize = panelFontSize; var labelFontSize = panelFontSize; var closeBtnFontSize = panelFontSize; var infoFontSize = panelFontSize; var titleFontSize = panelFontSize; // Panel boyutları ve konum (resize for larger text/buttons) var rowH = 80 + 8; var panelW = 1200 + 120; var panelH = 1200 + 2 * rowH; var px = 1024, py = 900; // Panel BG window.resourceTradePanelBG = LK.getAsset('resource', { anchorX: 0.5, anchorY: 0.5, x: px, y: py, scaleX: panelW / 40, scaleY: panelH / 40, tint: 0x223355, alpha: 0.97 }); // Başlık window.resourceTradePanelTitle = new Text2("Hammadde Takası", { size: titleFontSize, fill: 0x00ffcc, align: "center" }); window.resourceTradePanelTitle.anchor.set(0.5, 0); window.resourceTradePanelTitle.x = px; window.resourceTradePanelTitle.y = py - panelH / 2 + 40; // Bilgi yazısı window.resourceTradePanelInfoText = new Text2("Elinizdeki hammaddeleri takas edebilirsiniz.\nHer hammaddenin değeri 5-30 arası değişir ve her 5 saniyede güncellenir.", { size: infoFontSize, fill: 0xffffff, align: "center" }); window.resourceTradePanelInfoText.anchor.set(0.5, 0); window.resourceTradePanelInfoText.x = px; window.resourceTradePanelInfoText.y = window.resourceTradePanelTitle.y + 60; // Kapat butonu window.resourceTradePanelCloseBtn = new Text2("Kapat", { size: unifiedFontSize + 4, // 2 font larger than Coins fill: 0xff4444, align: "center" }); window.resourceTradePanelCloseBtn.anchor.set(0.5, 0.5); window.resourceTradePanelCloseBtn.x = px; window.resourceTradePanelCloseBtn.y = window.resourceTradePanelTitle.y - 110; // further above title // Hammadde satırları ve butonları window.resourceTradeLabels = []; window.resourceTradeSellBtns = []; window.resourceTradeSellAllBtns = []; window.resourceTradeBuyBtns = []; var startY = window.resourceTradePanelInfoText.y + 80 + rowH; // move all rows down by 1 row for (var i = 0; i < window.resourceLabelOrder.length; i++) { var resObj = window.resourceLabelOrder[i]; var idx = resObj.origIdx; var label = new Text2(resObj.name + ": " + (playerResources[idx] || 0) + " | Değer: " + (window.resourceTradeValues ? window.resourceTradeValues[idx] : 0), { size: labelFontSize, fill: 0xffffff, align: "left" }); label.anchor.set(0, 0.5); label.x = px - panelW / 2 + 60; label.y = startY + i * rowH; window.resourceTradeLabels.push(label); // Sat butonu var sellBtn = new Text2("Sat", { size: panelBtnFontSize, fill: 0x00ff99, align: "center" }); sellBtn.anchor.set(0.5, 0.5); sellBtn.x = px + 220; sellBtn.y = label.y; sellBtn._resourceIdx = idx; window.resourceTradeSellBtns.push(sellBtn); // Tümünü Sat butonu var sellAllBtn = new Text2("Tümünü Sat", { size: panelBtnFontSize, fill: 0x00cc99, align: "center" }); sellAllBtn.anchor.set(0.5, 0.5); sellAllBtn.x = px + 400; sellAllBtn.y = label.y; sellAllBtn._resourceIdx = idx; window.resourceTradeSellAllBtns.push(sellAllBtn); // Al butonu var buyBtn = new Text2("Al", { size: panelBtnFontSize, fill: 0x0099ff, align: "center" }); buyBtn.anchor.set(0.5, 0.5); buyBtn.x = px + 580; buyBtn.y = label.y; buyBtn._resourceIdx = idx; window.resourceTradeBuyBtns.push(buyBtn); } // Add to game game.addChild(window.resourceTradePanelBG); game.addChild(window.resourceTradePanelTitle); game.addChild(window.resourceTradePanelInfoText); game.addChild(window.resourceTradePanelCloseBtn); for (var i = 0; i < window.resourceTradeLabels.length; i++) game.addChild(window.resourceTradeLabels[i]); for (var i = 0; i < window.resourceTradeSellBtns.length; i++) game.addChild(window.resourceTradeSellBtns[i]); for (var i = 0; i < window.resourceTradeSellAllBtns.length; i++) game.addChild(window.resourceTradeSellAllBtns[i]); for (var i = 0; i < window.resourceTradeBuyBtns.length; i++) game.addChild(window.resourceTradeBuyBtns[i]); // Panel güncelleme fonksiyonu window.updateResourceTradePanel = function () { for (var i = 0; i < window.resourceLabelOrder.length; i++) { var resObj = window.resourceLabelOrder[i]; var idx = resObj.origIdx; if (window.resourceTradeLabels[i]) { window.resourceTradeLabels[i].setText(resObj.name + ": " + (playerResources[idx] || 0) + " | Değer: " + (window.resourceTradeValues ? window.resourceTradeValues[idx] : 0)); } } }; window.updateResourceTradePanel(); }; window.closeResourceTradePanel = function () { if (!window.resourceTradePanelState.open) return; window.resourceTradePanelState.open = false; if (window.resourceTradePanelBG && window.resourceTradePanelBG.parent) window.resourceTradePanelBG.parent.removeChild(window.resourceTradePanelBG); if (window.resourceTradePanelTitle && window.resourceTradePanelTitle.parent) window.resourceTradePanelTitle.parent.removeChild(window.resourceTradePanelTitle); if (window.resourceTradePanelInfoText && window.resourceTradePanelInfoText.parent) window.resourceTradePanelInfoText.parent.removeChild(window.resourceTradePanelInfoText); if (window.resourceTradePanelCloseBtn && window.resourceTradePanelCloseBtn.parent) window.resourceTradePanelCloseBtn.parent.removeChild(window.resourceTradePanelCloseBtn); if (window.resourceTradeLabels) for (var i = 0; i < window.resourceTradeLabels.length; i++) if (window.resourceTradeLabels[i] && window.resourceTradeLabels[i].parent) window.resourceTradeLabels[i].parent.removeChild(window.resourceTradeLabels[i]); if (window.resourceTradeSellBtns) for (var i = 0; i < window.resourceTradeSellBtns.length; i++) if (window.resourceTradeSellBtns[i] && window.resourceTradeSellBtns[i].parent) window.resourceTradeSellBtns[i].parent.removeChild(window.resourceTradeSellBtns[i]); if (window.resourceTradeSellAllBtns) for (var i = 0; i < window.resourceTradeSellAllBtns.length; i++) if (window.resourceTradeSellAllBtns[i] && window.resourceTradeSellAllBtns[i].parent) window.resourceTradeSellAllBtns[i].parent.removeChild(window.resourceTradeSellAllBtns[i]); if (window.resourceTradeBuyBtns) for (var i = 0; i < window.resourceTradeBuyBtns.length; i++) if (window.resourceTradeBuyBtns[i] && window.resourceTradeBuyBtns[i].parent) window.resourceTradeBuyBtns[i].parent.removeChild(window.resourceTradeBuyBtns[i]); window.resourceTradePanelBG = null; window.resourceTradePanelTitle = null; window.resourceTradePanelInfoText = null; window.resourceTradePanelCloseBtn = null; window.resourceTradeLabels = null; window.resourceTradeSellBtns = null; window.resourceTradeSellAllBtns = null; window.resourceTradeBuyBtns = null; }; var healthText = new Text2('Health: 100/100', { size: unifiedFontSize, fill: 0x00FF00 }); healthText.anchor.set(0.5, 0); healthText._isHealthBar = true; // Mark for tap detection LK.gui.top.addChild(healthText); var shieldText = new Text2('Shield: 50/50', { size: unifiedFontSize, fill: 0x0088FF }); shieldText.anchor.set(0.5, 0); shieldText.y = 60; LK.gui.top.addChild(shieldText); // --- Add waveText and expText UI for wave/level display --- // --- REPAIR PANEL WARNING SUPPRESSION --- // When repair panel is closed, set a suppression timer for 30 seconds (1800 ticks) if (window.repairPanel && !window._repairPanelSuppressUntil) { window._repairPanelSuppressUntil = LK.ticks + 1800; } // (removed duplicate handler, see main game.down below) var waveText = new Text2('Wave: 1', { size: unifiedFontSize, fill: 0xffffff }); waveText.anchor.set(0.5, 0); waveText.x = 1024; waveText.y = 60; // Move down to make space for market button LK.gui.top.addChild(waveText); var expText = new Text2('Level: 1 EXP: 0/10', { size: unifiedFontSize, fill: 0xffffff }); expText.anchor.set(0.5, 0); expText.x = 1024; expText.y = 70; LK.gui.top.addChild(expText); // No wave, minimap, exp, or coordinate UI in this version // Create joystick joystickBase = game.addChild(LK.getAsset('joystickBase', { anchorX: 0.5, anchorY: 0.5, x: 300, y: 2432 })); joystickBase.alpha = 0.5; joystickHandle = game.addChild(LK.getAsset('joystickHandle', { anchorX: 0.5, anchorY: 0.5, x: 300, y: 2432 })); joystickHandle.alpha = 0.7; // Create ship ship = game.addChild(new Ship()); ship.x = 1024; ship.y = 1366; // Add health bar to ship ship._healthBar = new HealthBar(); ship._healthBar.set({ maxValue: function maxValue() { return ship.maxHealth; }, getValueFn: function getValueFn() { return ship.health; }, getMaxFn: function getMaxFn() { return ship.maxHealth; }, width: 80, height: 12 }); ship._healthBar.y = -70; ship.addChild(ship._healthBar); // Start background music LK.playMusic('bgmusic'); // Initialize star field (increased by 50%) and make them colorful for (var i = 0; i < 135; i++) { // 90 * 1.5 = 135 spawnStar(true); // pass true to enable colorful stars } // Spawn more map elements at start (20% more) for (var i = 0; i < 6; i++) { // was 5, now 6 spawnNPC(); } for (var i = 0; i < 6; i++) { // was 5, now 6 spawnPirate(); } for (var i = 0; i < 4; i++) { // was 5, now 4 (20% reduction) spawnAsteroid(); } // Helper functions function spawnStar(colorful) { var star = new Star(); // If colorful is true, assign a random color if (colorful) { // Pick a random color from a vibrant palette var palette = [0xffe066, // yellow 0xff66cc, // pink 0x66ffcc, // aqua 0x66ccff, // blue 0xcc66ff, // purple 0xff6666, // red 0x66ff66, // green 0xffffff, // white 0xffcc66, // orange 0x66ffff // cyan ]; var color = palette[Math.floor(Math.random() * palette.length)]; if (star.children && star.children.length > 0 && star.children[0]) { star.children[0].tint = color; } } // Spawn at a random position within a large area around the ship var radius = 1800 + Math.random() * 1200; // 1800-3000 px from ship var angle = Math.random() * Math.PI * 2; star.x = ship.x + Math.cos(angle) * radius; star.y = ship.y + Math.sin(angle) * radius; stars.push(star); game.addChild(star); } function spawnNPC() { var npc = new NPC(); // Spawn from edges of visible area var edge = Math.floor(Math.random() * 4); switch (edge) { case 0: // Top npc.x = ship.x + (Math.random() - 0.5) * 2000; npc.y = ship.y - 1500; break; case 1: // Right npc.x = ship.x + 1500; npc.y = ship.y + (Math.random() - 0.5) * 2000; break; case 2: // Bottom npc.x = ship.x + (Math.random() - 0.5) * 2000; npc.y = ship.y + 1500; break; case 3: // Left npc.x = ship.x - 1500; npc.y = ship.y + (Math.random() - 0.5) * 2000; break; } npc.baseY = npc.y; // --- Set NPC level and health to match pirate scaling --- var minLevel = 1 + waveNumber * 2; var maxLevel = minLevel + 2; npc.level = minLevel + Math.floor(Math.random() * (maxLevel - minLevel + 1)); npc.health = 100 + (npc.level - 1) * 10; // Add health bar to NPC (for defend/hunt/escort/delivery/explore) npc._healthBar = new HealthBar(); npc._healthBar.set({ maxValue: function maxValue() { return npc.health !== undefined ? npc.health : 100; }, getValueFn: function getValueFn() { return npc.health !== undefined ? npc.health : 100; }, getMaxFn: function getMaxFn() { return 100 + (npc.level - 1) * 10; }, width: 60, height: 10 }); npc._healthBar.y = -60; npc.addChild(npc._healthBar); npcs.push(npc); game.addChild(npc); } function spawnPirate() { var pirate = new Pirate(); // Spawn from edges of visible area var edge = Math.floor(Math.random() * 4); switch (edge) { case 0: // Top pirate.x = ship.x + (Math.random() - 0.5) * 1800; pirate.y = ship.y - 1400; break; case 1: // Right pirate.x = ship.x + 1400; pirate.y = ship.y + (Math.random() - 0.5) * 1800; break; case 2: // Bottom pirate.x = ship.x + (Math.random() - 0.5) * 1800; pirate.y = ship.y + 1400; break; case 3: // Left pirate.x = ship.x - 1400; pirate.y = ship.y + (Math.random() - 0.5) * 1800; break; } // Set pirate level and scale stats based on wave // Level range: wave 1 => 1-3, wave 2 => 3-5, wave 3 => 5-7, etc. var minLevel = 1 + waveNumber * 2; var maxLevel = minLevel + 2; pirate.level = minLevel + Math.floor(Math.random() * (maxLevel - minLevel + 1)); pirate.health = 30 + (pirate.level - 1) * 10; pirate.damage = 5 + Math.floor((pirate.level - 1) * 1.5); pirate.defense = 2 + Math.floor((pirate.level - 1) * 1.2); // Add health bar to pirate pirate._healthBar = new HealthBar(); pirate._healthBar.set({ maxValue: function maxValue() { return pirate.health > 0 ? pirate.health : 0; }, getValueFn: function getValueFn() { return pirate.health > 0 ? pirate.health : 0; }, getMaxFn: function getMaxFn() { return 30 + waveNumber * 10; }, width: 60, height: 10 }); pirate._healthBar.y = -60; pirate.addChild(pirate._healthBar); pirates.push(pirate); game.addChild(pirate); } function spawnAsteroid() { var asteroid = new Asteroid(); var edge = Math.floor(Math.random() * 4); switch (edge) { case 0: asteroid.x = ship.x + (Math.random() - 0.5) * 2200; asteroid.y = ship.y - 1600; break; case 1: asteroid.x = ship.x + 1600; asteroid.y = ship.y + (Math.random() - 0.5) * 2200; break; case 2: asteroid.x = ship.x + (Math.random() - 0.5) * 2200; asteroid.y = ship.y + 1600; break; case 3: asteroid.x = ship.x - 1600; asteroid.y = ship.y + (Math.random() - 0.5) * 2200; break; } // Add health bar to asteroid asteroid._healthBar = new HealthBar(); asteroid._healthBar.set({ maxValue: function maxValue() { return asteroid.health; }, getValueFn: function getValueFn() { return asteroid.health; }, getMaxFn: function getMaxFn() { return 50; }, width: 50, height: 8 }); asteroid._healthBar.y = -50; asteroid.addChild(asteroid._healthBar); asteroids.push(asteroid); game.addChild(asteroid); } // No upgrade stations in this version // No trade stations in this version function createExplosion(x, y) { for (var i = 0; i < 8; i++) { var particle = LK.getAsset('explosion', { anchorX: 0.5, anchorY: 0.5, x: x, y: y }); particle.vx = (Math.random() - 0.5) * 10; particle.vy = (Math.random() - 0.5) * 10; particle.life = 30; explosions.push(particle); game.addChild(particle); } } // No black holes or wormholes in this version function updateUI() { coinText.setText('Coins: ' + playerCoins); // Keep playerMetal/playerEnergy in sync with playerResources playerMetal = playerResources[0]; playerEnergy = playerResources[1]; // Use sorted resource label order for display if (window.resourceLabels && window.resourceLabelOrder && window.resourceLabels.length === window.resourceLabelOrder.length) { for (var i = 0; i < window.resourceLabelOrder.length; i++) { var resObj = window.resourceLabelOrder[i]; window.resourceLabels[i].setText(resObj.name + ': ' + (playerResources[resObj.origIdx] || 0)); } } // (No market price display) var healthPercent = Math.round(ship.health / ship.maxHealth * 100); healthText.setText('Health: %' + healthPercent); var shieldPercent = Math.round(ship.shield / ship.maxShield * 100); shieldText.setText('Shield: %' + shieldPercent); // Restore wave and exp UI if (typeof waveText !== "undefined") { waveText.setText('Wave: ' + (waveNumber + 1)); } if (typeof expText !== "undefined") { expText.setText('Level: ' + playerLevel + ' EXP: ' + playerEXP + '/' + expToNext(playerLevel)); } waveText.setText('Wave: ' + (waveNumber + 1)); expText.setText('Level: ' + playerLevel + ' EXP: ' + playerEXP + '/' + expToNext(playerLevel)); // Show player level/exp in GUI (top right, above repText) if (!window.levelText) { window.levelText = new Text2('Seviye: ' + playerLevel + ' EXP: ' + playerEXP + '/' + expToNext(playerLevel), { size: unifiedFontSize, fill: 0xffffff }); window.levelText.anchor.set(1, 0); window.levelText.x = -20; window.levelText.y = 20; // moved up by one row (40px) LK.gui.topRight.addChild(window.levelText); } window.levelText.setText('Seviye: ' + playerLevel + ' EXP: ' + playerEXP + '/' + expToNext(playerLevel)); // Update player level/exp in top right if (window.levelText) { window.levelText.setText('Seviye: ' + playerLevel + ' EXP: ' + playerEXP + '/' + expToNext(playerLevel)); } // Update health text color if (ship.health > 60) { healthText.fill = 0x00ff00; } else if (ship.health > 30) { healthText.fill = 0xffff00; } else { healthText.fill = 0xff0000; } // Update shield text color if (ship.shield > 30) { shieldText.fill = 0x0088ff; } else if (ship.shield > 10) { shieldText.fill = 0xffff00; } else { shieldText.fill = 0xff0000; } storage.playerLevel = playerLevel; storage.playerEXP = playerEXP; } function saveProgress() { storage.coins = playerCoins; var resourceKeys = ['metal', 'energy', 'crystal', 'gas', 'ice', 'uranium', 'silicon', 'carbon', 'plasma', 'antimatter']; for (var i = 0; i < resourceKeys.length; i++) { storage[resourceKeys[i]] = playerResources[i] || 0; } // Keep playerMetal/playerEnergy in sync with playerResources playerMetal = playerResources[0]; playerEnergy = playerResources[1]; storage.questsCompleted = questsCompleted; } // Event handlers game.down = function (x, y, obj) { // --- GLOBAL MARKET BUTTON HANDLER (exact image area) --- if (window.globalMarketBtn && window.globalMarketBtn.parent) { var btn = window.globalMarketBtn; var bx = btn.x, by = btn.y; var bw = btn.width || 320, bh = btn.height || 80; // LK.gui.bottomRight is anchored at (1,1), so x,y negative from bottom right // The area is anchored at (1,1), so its (x,y) is the bottom right corner of the area // So the area covers (bx-bw, by-bh) to (bx, by) if (x > 2048 + bx - bw && x < 2048 + bx && y > 2732 + by - bh && y < 2732 + by) { window.openResourceTradePanel(); return; } } // --- RESOURCE TRADE PANEL INDEPENDENT BUTTON HANDLER --- // If the independent button exists, check tap if (window.resourceTradePanelIndependentBtn && window.resourceTradePanelIndependentBtn.parent) { var btn = window.resourceTradePanelIndependentBtn; var bx = btn.x, by = btn.y; var bw = btn.width, bh = btn.height; // LK.gui.bottomRight is anchored at (1,1), so x,y negative from bottom right // The area is anchored at (1,1), so its (x,y) is the bottom right corner of the area // So the area covers (bx-bw, by-bh) to (bx, by) if (x > 2048 + bx - bw && x < 2048 + bx && y > 2732 + by - bh && y < 2732 + by) { // Open 'Hammadde Stoğu' panel if (typeof window.openResourceStockPanel === "function") { window.openResourceStockPanel(); } else { // Fallback: show a simple panel with player's resource stock if (window._resourceStockPanel) return; var panelW = 900, panelH = 900; var px = 1024, py = 900; // Increase font size by 2 for all panel texts/buttons var panelFontSize = unifiedFontSize + 2; var labelFontSize = panelFontSize; var closeBtnFontSize = panelFontSize; var titleFontSize = panelFontSize; // Resize panel background to fit enlarged text/buttons var rowH = 70 + 8; var panelW = 900 + 120; var panelH = 900 + 2 * rowH; var bg = LK.getAsset('resource', { anchorX: 0.5, anchorY: 0.5, x: px, y: py, scaleX: panelW / 40, scaleY: panelH / 40, tint: 0x223355, alpha: 0.97 }); var title = new Text2("Hammadde Stoğu", { size: titleFontSize, fill: 0x00ffcc, align: "center" }); title.anchor.set(0.5, 0); title.x = px; title.y = py - panelH / 2 + 40; // List resources var labels = []; var startY = title.y + 80; for (var i = 0; i < window.resourceLabelOrder.length; i++) { var resObj = window.resourceLabelOrder[i]; var idx = resObj.origIdx; var label = new Text2(resObj.name + ": " + (playerResources[idx] || 0), { size: labelFontSize, fill: 0xffffff, align: "left" }); label.anchor.set(0, 0.5); label.x = px - panelW / 2 + 60; label.y = startY + i * rowH; labels.push(label); } // Close button var closeBtn = new Text2("Kapat", { size: unifiedFontSize + 4, // 2 font larger than Coins fill: 0xff4444, align: "center" }); closeBtn.anchor.set(0.5, 0.5); closeBtn.x = px; closeBtn.y = title.y - 110; // above the title // Add to game game.addChild(bg); game.addChild(title); for (var i = 0; i < labels.length; i++) game.addChild(labels[i]); game.addChild(closeBtn); // Store refs for tap logic/cleanup window._resourceStockPanel = { bg: bg, title: title, labels: labels, closeBtn: closeBtn }; // Add close logic closeBtn._isResourceStockCloseBtn = true; } return; } } // --- RESOURCE TRADE PANEL HANDLER --- if (window._resourceStockPanel && window._resourceStockPanel.closeBtn) { var btn = window._resourceStockPanel.closeBtn; var bx = btn.x, by = btn.y; var bw = btn.width || 300, bh = btn.height || 80; if (x > bx - bw / 2 && x < bx + bw / 2 && y > by - bh / 2 && y < by + bh / 2) { // Remove all panel elements if (window._resourceStockPanel.bg && window._resourceStockPanel.bg.parent) window._resourceStockPanel.bg.parent.removeChild(window._resourceStockPanel.bg); if (window._resourceStockPanel.title && window._resourceStockPanel.title.parent) window._resourceStockPanel.title.parent.removeChild(window._resourceStockPanel.title); if (window._resourceStockPanel.labels) for (var i = 0; i < window._resourceStockPanel.labels.length; i++) if (window._resourceStockPanel.labels[i] && window._resourceStockPanel.labels[i].parent) window._resourceStockPanel.labels[i].parent.removeChild(window._resourceStockPanel.labels[i]); if (window._resourceStockPanel.closeBtn && window._resourceStockPanel.closeBtn.parent) window._resourceStockPanel.closeBtn.parent.removeChild(window._resourceStockPanel.closeBtn); window._resourceStockPanel = null; return; } } if (window.resourceTradePanelState && window.resourceTradePanelState.open) { // Close btn if (window.resourceTradePanelCloseBtn) { var bx = window.resourceTradePanelCloseBtn.x, by = window.resourceTradePanelCloseBtn.y; var bw = window.resourceTradePanelCloseBtn.width || 300, bh = window.resourceTradePanelCloseBtn.height || 80; if (x > bx - bw / 2 && x < bx + bw / 2 && y > by - bh / 2 && y < by + bh / 2) { window.closeResourceTradePanel(); return; } } // Sat btns if (window.resourceTradeSellBtns) { for (var i = 0; i < window.resourceTradeSellBtns.length; i++) { var btn = window.resourceTradeSellBtns[i]; var bx = btn.x, by = btn.y; var bw = btn.width || 120, bh = btn.height || 60; if (x > bx - bw / 2 && x < bx + bw / 2 && y > by - bh / 2 && y < by + bh / 2) { var idx = btn._resourceIdx; var amount = playerResources[idx] || 0; var value = window.resourceTradeValues ? window.resourceTradeValues[idx] : 0; if (amount > 0 && value > 0) { playerCoins += value * amount; playerResources[idx] = 0; btn.setText("Satıldı!"); btn.fill = 0x00ffcc; if (window.updateResourceTradePanel) window.updateResourceTradePanel(); updateUI(); saveProgress(); } else { btn.setText("Yok!"); btn.fill = 0xff4444; } // Reset label after short delay (function (b, orig, origFill) { LK.setTimeout(function () { b.setText("Sat"); b.fill = 0x00ff99; }, 700); })(btn, "Sat", 0x00ff99); return; } } } // Tümünü Sat btns if (window.resourceTradeSellAllBtns) { for (var i = 0; i < window.resourceTradeSellAllBtns.length; i++) { var btn = window.resourceTradeSellAllBtns[i]; var bx = btn.x, by = btn.y; var bw = btn.width || 180, bh = btn.height || 60; if (x > bx - bw / 2 && x < bx + bw / 2 && y > by - bh / 2 && y < by + bh / 2) { var idx = btn._resourceIdx; var amount = playerResources[idx] || 0; var value = window.resourceTradeValues ? window.resourceTradeValues[idx] : 0; if (amount > 0 && value > 0) { playerCoins += value * amount; playerResources[idx] = 0; btn.setText("Hepsi Satıldı!"); btn.fill = 0x00ffcc; if (window.updateResourceTradePanel) window.updateResourceTradePanel(); updateUI(); saveProgress(); } else { btn.setText("Yok!"); btn.fill = 0xff4444; } (function (b, orig, origFill) { LK.setTimeout(function () { b.setText("Tümünü Sat"); b.fill = 0x00cc99; }, 700); })(btn, "Tümünü Sat", 0x00cc99); return; } } } // Al btns if (window.resourceTradeBuyBtns) { for (var i = 0; i < window.resourceTradeBuyBtns.length; i++) { var btn = window.resourceTradeBuyBtns[i]; var bx = btn.x, by = btn.y; var bw = btn.width || 120, bh = btn.height || 60; if (x > bx - bw / 2 && x < bx + bw / 2 && y > by - bh / 2 && y < by + bh / 2) { var idx = btn._resourceIdx; var value = window.resourceTradeValues ? window.resourceTradeValues[idx] : 0; // Satın alma miktarı: 1 (veya istenirse artırılabilir) var buyAmount = 1; var totalCost = value * buyAmount; if (playerCoins >= totalCost && value > 0) { playerCoins -= totalCost; playerResources[idx] = (playerResources[idx] || 0) + buyAmount; btn.setText("Alındı!"); btn.fill = 0x00ffcc; if (window.updateResourceTradePanel) window.updateResourceTradePanel(); updateUI(); saveProgress(); } else { btn.setText("Yetersiz coin!"); btn.fill = 0xff4444; } (function (b, orig, origFill) { LK.setTimeout(function () { b.setText("Al"); b.fill = 0x0099ff; }, 700); })(btn, "Al", 0x0099ff); return; } } } // Block all other taps when panel is open return; } // --- UZAY İSTASYONU TESLİMAT BUTTON HANDLER --- // Handle tap on stationDeliveryBtnArea (transparent area, exactly image size) if (window.stationDeliveryBtnArea && window.stationDeliveryBtnArea.parent) { var btn = window.stationDeliveryBtnArea; var bx = btn.x, by = btn.y; var bw = btn.width, bh = btn.height; // LK.gui.bottomRight is anchored at (1,1), so x,y negative from bottom right // The area is anchored at (1,1), so its (x,y) is the bottom right corner of the area // So the area covers (bx-bw, by-bh) to (bx, by) if (x > 2048 + bx - bw && x < 2048 + bx && y > 2732 + by - bh && y < 2732 + by) { window.openStationDeliveryPanel(); return; } } // LK.gui.bottomRight is anchored at (1,1), so x,y negative from bottom right if (window.stationDeliveryBtn && window.stationDeliveryBtn.parent) { var btn = window.stationDeliveryBtn; var bx = btn.x, by = btn.y; // Button is about 180x80 px, so check if x is within 200px of right edge and y within 300-480px of bottom if (x > 2048 - 200 && y > 2732 - 300 && y < 2732 - 100) { window.openStationDeliveryPanel(); return; } } // --- UZAY İSTASYONU TESLİMAT PANEL HANDLER --- if (window.stationDeliveryPanel) { // Close btn if (window.stationDeliveryPanelCloseBtn) { var bx = window.stationDeliveryPanelCloseBtn.x, by = window.stationDeliveryPanelCloseBtn.y; var bw = window.stationDeliveryPanelCloseBtn.width || 300, bh = window.stationDeliveryPanelCloseBtn.height || 80; if (x > bx - bw / 2 && x < bx + bw / 2 && y > by - bh / 2 && y < by + bh / 2) { window.closeStationDeliveryPanel(); return; } } // Teslim Et btns if (window.stationDeliveryDeliverBtns) { for (var i = 0; i < window.stationDeliveryDeliverBtns.length; i++) { var btn = window.stationDeliveryDeliverBtns[i]; var bx = btn.x, by = btn.y; var bw = btn.width || 120, bh = btn.height || 60; if (x > bx - bw / 2 && x < bx + bw / 2 && y > by - bh / 2 && y < by + bh / 2) { var idx = btn._stationResIdx; var req = window.stationDeliveryState.requests[idx]; var delivered = window.stationDeliveryState.delivered[idx]; var canDeliver = Math.min(playerResources[idx], req - delivered); if (canDeliver > 0) { playerResources[idx] -= canDeliver; window.stationDeliveryState.delivered[idx] += canDeliver; btn.setText("Teslim Edildi!"); btn.fill = 0x00ffcc; // Update label if (window.stationDeliveryLabels && window.stationDeliveryLabels[i]) { window.stationDeliveryLabels[i].setText(window.resourceLabelOrder[i].name + ": " + window.stationDeliveryState.delivered[idx] + " / " + req); } updateUI(); saveProgress(); } else { btn.setText("Yok!"); btn.fill = 0xff4444; } // Reset label after short delay (function (b, orig, origFill) { LK.setTimeout(function () { b.setText(orig); b.fill = origFill; }, 700); })(btn, "Teslim Et", 0x00ff99); return; } } } // Teslimatı Tamamla (ödül al) butonu if (window.stationDeliveryPanelClaimBtn) { var btn = window.stationDeliveryPanelClaimBtn; var bx = btn.x, by = btn.y; var bw = btn.width || 400, bh = btn.height || 80; if (x > bx - bw / 2 && x < bx + bw / 2 && y > by - bh / 2 && y < by + bh / 2) { // Check if all delivered var allDone = true; for (var i = 0; i < 10; i++) { if (window.stationDeliveryState.delivered[i] < window.stationDeliveryState.requests[i]) { allDone = false; break; } } if (allDone && !window.stationDeliveryState.rewardClaimed) { // Calculate total value (normal market price * delivered) * (1+bonus%) var totalValue = 0; for (var i = 0; i < 10; i++) { var price = 1; // Market removed, use static price totalValue += price * window.stationDeliveryState.requests[i]; } var bonus = window.stationDeliveryState.bonus; var reward = Math.round(totalValue * (1 + bonus / 100)); playerCoins += reward; window.stationDeliveryState.rewardClaimed = true; btn.setText("Ödül Alındı! +" + reward + " coin"); btn.fill = 0x00ffcc; // Show floating label var label = new Text2("İstasyon Teslimatı Tamamlandı!\n+" + reward + " coin", { size: 48, fill: 0xffcc00, align: "center" }); label.anchor.set(0.5, 0.5); label.x = 1024; label.y = 600; game.addChild(label); LK.setTimeout(function () { if (label.parent) label.parent.removeChild(label); }, 1800); updateUI(); saveProgress(); } else if (window.stationDeliveryState.rewardClaimed) { btn.setText("Zaten Alındı!"); btn.fill = 0x888888; } else { btn.setText("Eksik Teslimat!"); btn.fill = 0xff4444; } // Reset label after short delay (function (b, orig, origFill) { LK.setTimeout(function () { b.setText("Tümünü Teslim Et & Ödülü Al"); b.fill = 0xffcc00; }, 1200); })(btn, "Tümünü Teslim Et & Ödülü Al", 0xffcc00); return; } } // Block all other taps when panel is open return; } // --- RESET BUTTON HANDLER --- if (game._resetBtn && game._resetBtn.parent) { // Convert GUI coordinates for bottomRight // LK.gui.bottomRight is anchored at (1,1) so x,y are negative from bottom right var btn = game._resetBtn; var bx = btn.x, by = btn.y; // Button is about 180x80 px, but let's use a safe area // Since anchor is (1,1), bottom right, and x/y are negative from bottom right // So, for a tap, check if x is within 200px of right edge and y within 100px of bottom // LK.gui.bottomRight: x=0,y=0 is bottom right, so x,y negative if (x > 2048 - 200 && y > 2732 - 100) { // Clear all persistent storage storage.coins = 0; storage.metal = 0; storage.energy = 0; storage.crystal = 0; storage.gas = 0; storage.ice = 0; storage.uranium = 0; storage.silicon = 0; storage.carbon = 0; storage.plasma = 0; storage.antimatter = 0; storage.questsCompleted = 0; storage.playerLevel = 1; storage.playerEXP = 0; // Optionally clear any other custom progress keys // Show a quick feedback btn.setText("Reset!"); btn.fill = 0x00ff99; // Reload game (reset all progress) LK.showGameOver(); return; } } // --- MINI MAP BUTTON HANDLER --- if (game._miniMapBtn && game._miniMapBtn.parent) { // Mini map button is about 180x80 px, left of Reset // x: 2048 - 400 to 2048 - 220, y: 2732 - 100 to 2732 if (x > 2048 - 400 && x < 2048 - 220 && y > 2732 - 100 && y < 2732) { window._miniMapVisible = !window._miniMapVisible; // If hiding, remove all mini map elements if (!window._miniMapVisible && window._miniMapContainer && window._miniMapContainer.parent) { window._miniMapContainer.parent.removeChild(window._miniMapContainer); window._miniMapElements = []; window._miniMapContainer = null; } // If showing, force a minimap update by calling the minimap overlay logic if (window._miniMapVisible) { // The minimap overlay is drawn in the main game loop, so we just need to trigger a redraw // by setting _miniMapVisible = true. The next game.update will draw it. // Optionally, we can force a redraw immediately by calling game.update() if needed. if (typeof game.update === "function") { game.update(); } } return; } } // --- NPC ile savaş butonu handler --- if (window.npcFightBtn) { var bx = window.npcFightBtn.x, by = window.npcFightBtn.y; var bw = window.npcFightBtn.width || 400, bh = window.npcFightBtn.height || 100; // Accept generous tap area if (x > bx - bw / 2 && x < bx + bw / 2 && y > by - bh / 2 && y < by + bh / 2) { window.npcFightMode = !window.npcFightMode; if (window.npcFightMode) { window.npcFightBtn.setText("NPC Savaş: AÇIK"); window.npcFightBtn.fill = 0xff0000; } else { window.npcFightBtn.setText("NPC ile Savaş"); window.npcFightBtn.fill = 0xff4444; } return; } } if (window.repairPanel && window.repairBtn && window.repairBtn.parent) { // Check tap on repair button var btn = window.repairBtn; var bx = btn.x, by = btn.y; if (x > bx - 90 && x < bx + 90 && y > by - 40 && y < by + 40) { // Try to repair var costCoins = btn._repairCostCoins, costMetal = btn._repairCostMetal, costEnergy = btn._repairCostEnergy; if (playerCoins >= costCoins && playerMetal >= costMetal && playerEnergy >= costEnergy) { playerCoins -= costCoins; playerMetal -= costMetal; playerEnergy -= costEnergy; ship.health = ship.maxHealth; updateUI(); saveProgress(); // Show feedback btn.setText("Tamir Edildi!"); btn.fill = 0x00ffcc; // Remove panel after short delay var expire = LK.ticks + 40; var origUpdate = game.update; game.update = function () { if (LK.ticks > expire) { if (window.repairPanel && window.repairPanel.parent) window.repairPanel.parent.removeChild(window.repairPanel); if (window.repairText && window.repairText.parent) window.repairText.parent.removeChild(window.repairText); if (window.repairBtn && window.repairBtn.parent) window.repairBtn.parent.removeChild(window.repairBtn); if (window.cancelRepairBtn && window.cancelRepairBtn.parent) window.cancelRepairBtn.parent.removeChild(window.cancelRepairBtn); window.repairPanel = null; window.repairText = null; window.repairBtn = null; window.cancelRepairBtn = null; game.update = origUpdate; } if (origUpdate) origUpdate.apply(game, arguments); }; } else { // Not enough resources btn.setText("Yetersiz kaynak!"); btn.fill = 0xff4444; } return; } // Check tap on cancel button var cbtn = window.cancelRepairBtn; if (cbtn) { var cbx = cbtn.x, cby = cbtn.y; if (x > cbx - 90 && x < cbx + 90 && y > cby - 40 && y < cby + 40) { // Remove all repair panel elements, allow closing even if not repaired if (window.repairPanel && window.repairPanel.parent) window.repairPanel.parent.removeChild(window.repairPanel); if (window.repairText && window.repairText.parent) window.repairText.parent.removeChild(window.repairText); if (window.repairBtn && window.repairBtn.parent) window.repairBtn.parent.removeChild(window.repairBtn); if (window.cancelRepairBtn && window.cancelRepairBtn.parent) window.cancelRepairBtn.parent.removeChild(window.cancelRepairBtn); window.repairPanel = null; window.repairText = null; window.repairBtn = null; window.cancelRepairBtn = null; window._showRepairPanel = false; return; } } } // --- Health bar tap to show repair panel --- if (healthText && healthText.parent && healthText._isHealthBar && ship.health < ship.maxHealth && ship.health > 0) { // Get healthText bounds in screen coordinates // healthText is anchored at (0.5, 0), at top center // Let's estimate its bounds var hx = healthText.x, hy = healthText.y; var hw = healthText.width || 300; var hh = healthText.height || 60; // Accept generous tap area if (x > hx - hw / 2 && x < hx + hw / 2 && y > hy && y < hy + hh) { window._showRepairPanel = true; return; } } // --- SHIP TAP: Show upgrade/can-buy-health panel --- if (ship && ship.parent) { // Ship is at (ship.x, ship.y), size is 80x100 (see asset) var sx = ship.x, sy = ship.y; var sw = 80, sh = 100; // Accept generous tap area if (x > sx - sw / 2 && x < sx + sw / 2 && y > sy - sh / 2 && y < sy + sh / 2) { // Only show if not already shown if (!window.shipUpgradePanel) { // Panel background // --- DYNAMIC PANEL SIZE BASED ON CONTENT --- var upgBtnFont = unifiedFontSize; var upgBtnWidth = 340; var upgBtnHeight = 90; var colSpacing = 80; var colXOffset = upgBtnWidth / 2 + colSpacing / 2; var upgBtnSpacingY = 140; var numUpgradeRows = 4; // 3 upgrade rows + 1 buy health row var panelContentHeight = 100 + numUpgradeRows * upgBtnSpacingY + 2 * upgBtnHeight; // title + upgrades + buy health + speed + some margin var panelContentWidth = upgBtnWidth * 2 + colSpacing + 80; // two columns + spacing + margin // Add extra for speed upgrade and close button panelContentHeight += upgBtnSpacingY + 60; // speed upgrade + close btn margin // Clamp min/max var panelWidth = Math.max(700, Math.round(panelContentWidth)); var panelHeight = Math.max(340, Math.round(panelContentHeight)); var panel = LK.getAsset('resource', { anchorX: 0.5, anchorY: 0.5, x: sx, y: sy - 220, scaleX: panelWidth / 40, // asset is 40px wide scaleY: panelHeight / 40, // asset is 40px tall tint: 0x224488 }); // Title var titleFont = Math.round(62 * 1.1) - 3; var title = new Text2("Yükseltmeler & Can Satın Al", { size: titleFont, fill: 0xffffff, align: "center" }); title.anchor.set(0.5, 0.5); title.x = sx; title.y = sy - 220 - panelHeight / 2 + 100; // Upgrade buttons, dikeyde aralıklı ve panelin içine sığacak şekilde var upgBtnY = title.y + 110; var upgBtnSpacingY = 140; // Paneldeki yazı ve butonların font boyutunu, Wave font boyutu ile aynı yap var upgBtnFont = unifiedFontSize; var upgBtnWidth = 340; var upgBtnHeight = 90; var colSpacing = 80; var colXOffset = upgBtnWidth / 2 + colSpacing / 2; // Normal upgrades var upg1 = new Text2("Max Can +20\n(600 coin, 60 metal)", { size: upgBtnFont, fill: 0x00ff99, align: "center" }); upg1.anchor.set(0.5, 0.5); upg1.x = sx - colXOffset; upg1.y = upgBtnY; upg1._isShipUpgradeBtn = true; upg1._upgradeType = "maxHealth"; upg1._upgradeCost = { coins: 600, metal: 60, energy: 0 }; var upg1x2 = new Text2("Max Can +20\n(1200 coin, 120 metal)", { size: upgBtnFont, fill: 0x00cc99, align: "center" }); upg1x2.anchor.set(0.5, 0.5); upg1x2.x = sx + colXOffset; upg1x2.y = upgBtnY; upg1x2._isShipUpgradeBtn = true; upg1x2._upgradeType = "maxHealth"; upg1x2._upgradeCost = { coins: 1200, metal: 120, energy: 0 }; upg1x2._isDoubleCost = true; var upg2 = new Text2("Max Kalkan +10\n(720 coin, 72 metal)", { size: upgBtnFont, fill: 0x00ccff, align: "center" }); upg2.anchor.set(0.5, 0.5); upg2.x = sx - colXOffset; upg2.y = upgBtnY + upgBtnSpacingY; upg2._isShipUpgradeBtn = true; upg2._upgradeType = "maxShield"; upg2._upgradeCost = { coins: 720, metal: 72, energy: 0 }; var upg2x2 = new Text2("Max Kalkan +10\n(1440 coin, 144 metal)", { size: upgBtnFont, fill: 0x00aaff, align: "center" }); upg2x2.anchor.set(0.5, 0.5); upg2x2.x = sx + colXOffset; upg2x2.y = upgBtnY + upgBtnSpacingY; upg2x2._isShipUpgradeBtn = true; upg2x2._upgradeType = "maxShield"; upg2x2._upgradeCost = { coins: 1440, metal: 144, energy: 0 }; upg2x2._isDoubleCost = true; var upg3 = new Text2("Hasar +5\n(900 coin, 90 enerji)", { size: upgBtnFont, fill: 0xffcc00, align: "center" }); upg3.anchor.set(0.5, 0.5); upg3.x = sx - colXOffset; upg3.y = upgBtnY + upgBtnSpacingY * 2; upg3._isShipUpgradeBtn = true; upg3._upgradeType = "damage"; upg3._upgradeCost = { coins: 900, metal: 0, energy: 90 }; var upg3x2 = new Text2("Hasar +5\n(1800 coin, 180 enerji)", { size: upgBtnFont, fill: 0xff9900, align: "center" }); upg3x2.anchor.set(0.5, 0.5); upg3x2.x = sx + colXOffset; upg3x2.y = upgBtnY + upgBtnSpacingY * 2; upg3x2._isShipUpgradeBtn = true; upg3x2._upgradeType = "damage"; upg3x2._upgradeCost = { coins: 1800, metal: 0, energy: 180 }; upg3x2._isDoubleCost = true; // Buy health button (if not full) var canBuyHealth = ship.health < ship.maxHealth; var buyHealthBtnFont = unifiedFontSize; // Proportional cost scaling for buy health button var healthToRestore = ship.maxHealth - ship.health; var baseFullRepairHealth = 60; var baseCoinCost = 90 * 2; var baseMetalCost = 6 * 2; var baseEnergyCost = 6 * 2; var buyHealthCostCoins = Math.max(30, Math.round(baseCoinCost * (healthToRestore / baseFullRepairHealth))); var buyHealthCostMetal = Math.max(2, Math.round(baseMetalCost * (healthToRestore / baseFullRepairHealth))); var buyHealthCostEnergy = Math.max(2, Math.round(baseEnergyCost * (healthToRestore / baseFullRepairHealth))); var buyHealthBtn = new Text2("Canı Doldur (" + buyHealthCostCoins + " coin, " + buyHealthCostMetal + " metal, " + buyHealthCostEnergy + " enerji)", { size: buyHealthBtnFont, fill: canBuyHealth ? 0x00ffcc : 0x888888, align: "center" }); buyHealthBtn.anchor.set(0.5, 0.5); buyHealthBtn.x = sx; buyHealthBtn.y = upgBtnY + upgBtnSpacingY * 3 + 30; buyHealthBtn._isShipBuyHealthBtn = true; buyHealthBtn._repairCostCoins = buyHealthCostCoins; buyHealthBtn._repairCostMetal = buyHealthCostMetal; buyHealthBtn._repairCostEnergy = buyHealthCostEnergy; // Speed upgrade button (bottom of panel) var speedUpgLevel = window.shipSpeedUpgradeLevel || 0; var speedUpgFont = unifiedFontSize; var speedUpgCost = Math.round((120 + speedUpgLevel * 60) * 1.9); var speedUpgBtn = new Text2("Hız +" + Math.round((speedUpgLevel + 1) * 10) + "%\n(" + speedUpgCost + " coin)", { size: speedUpgFont, fill: 0x00ffff, align: "center" }); speedUpgBtn.anchor.set(0.5, 0.5); speedUpgBtn.x = sx; speedUpgBtn.y = buyHealthBtn.y + upgBtnSpacingY; speedUpgBtn._isShipSpeedUpgradeBtn = true; speedUpgBtn._speedUpgradeLevel = speedUpgLevel; speedUpgBtn._speedUpgradeCost = speedUpgCost; // Close button var closeBtn = new Text2("Kapat", { size: unifiedFontSize + 4, // 2 font larger than Coins fill: 0xff4444, align: "center" }); closeBtn.anchor.set(0.5, 0.5); // Move close button above the panel title, with extra margin closeBtn.x = sx; closeBtn.y = title.y - 110; // further above title closeBtn._isShipUpgradeCloseBtn = true; // Add to game game.addChild(panel); game.addChild(title); game.addChild(upg1); game.addChild(upg1x2); game.addChild(upg2); game.addChild(upg2x2); game.addChild(upg3); game.addChild(upg3x2); game.addChild(buyHealthBtn); game.addChild(speedUpgBtn); game.addChild(closeBtn); // Store refs for tap logic/cleanup window.shipUpgradePanel = panel; window.shipUpgradeTitle = title; window.shipUpgradeBtn1 = upg1; window.shipUpgradeBtn1x2 = upg1x2; window.shipUpgradeBtn2 = upg2; window.shipUpgradeBtn2x2 = upg2x2; window.shipUpgradeBtn3 = upg3; window.shipUpgradeBtn3x2 = upg3x2; window.shipBuyHealthBtn = buyHealthBtn; window.shipSpeedUpgradeBtn = speedUpgBtn; window.shipUpgradeCloseBtn = closeBtn; } return; } } if (Math.sqrt(Math.pow(x - joystickBase.x, 2) + Math.pow(y - joystickBase.y, 2)) < 100) { isDragging = true; joystickHandle.x = x; joystickHandle.y = y; } else { // --- SHIP UPGRADE PANEL BUTTONS --- if (window.shipUpgradePanel) { // Upgrade buttons var btns = [window.shipUpgradeBtn1, window.shipUpgradeBtn1x2, window.shipUpgradeBtn2, window.shipUpgradeBtn2x2, window.shipUpgradeBtn3, window.shipUpgradeBtn3x2]; for (var i = 0; i < btns.length; i++) { var btn = btns[i]; if (!btn) continue; var bx = btn.x, by = btn.y; if (x > bx - 120 && x < bx + 120 && y > by - 50 && y < by + 50) { // Try to buy upgrade var upg = btn._upgradeType; var cost = btn._upgradeCost; var isDouble = !!btn._isDoubleCost; if (upg === "maxHealth" && playerCoins >= cost.coins && playerMetal >= cost.metal) { ship.maxHealth += 20; ship.health = ship.maxHealth; playerCoins -= cost.coins; playerMetal -= cost.metal; LK.effects.flashObject(ship, isDouble ? 0x00cc99 : 0x00ff99, 400); btn.setText("Alındı!"); btn.fill = 0x00ffcc; updateUI(); saveProgress(); } else if (upg === "maxShield" && playerCoins >= cost.coins && playerMetal >= cost.metal) { ship.maxShield += 10; ship.shield = ship.maxShield; playerCoins -= cost.coins; playerMetal -= cost.metal; LK.effects.flashObject(ship, isDouble ? 0x00aaff : 0x00ccff, 400); btn.setText("Alındı!"); btn.fill = 0x00ffcc; updateUI(); saveProgress(); } else if (upg === "damage" && playerCoins >= cost.coins && playerEnergy >= cost.energy) { ship.damage += 5; playerCoins -= cost.coins; playerEnergy -= cost.energy; LK.effects.flashObject(ship, isDouble ? 0xff9900 : 0xffcc00, 400); btn.setText("Alındı!"); btn.fill = 0x00ffcc; updateUI(); saveProgress(); } else { btn.setText("Yetersiz kaynak!"); btn.fill = 0xff4444; } return; } } // Buy health button var bhb = window.shipBuyHealthBtn; if (bhb) { var bx = bhb.x, by = bhb.y; if (x > bx - 180 && x < bx + 180 && y > by - 50 && y < by + 50) { if (ship.health < ship.maxHealth) { var costCoins = bhb._repairCostCoins, costMetal = bhb._repairCostMetal, costEnergy = bhb._repairCostEnergy; if (playerCoins >= costCoins && playerMetal >= costMetal && playerEnergy >= costEnergy) { playerCoins -= costCoins; playerMetal -= costMetal; playerEnergy -= costEnergy; ship.health = ship.maxHealth; updateUI(); saveProgress(); bhb.setText("Can Dolduruldu!"); bhb.fill = 0x00ffcc; } else { bhb.setText("Yetersiz kaynak!"); bhb.fill = 0xff4444; } } else { bhb.setText("Can zaten tam!"); bhb.fill = 0x888888; } return; } } // Speed upgrade button var sub = window.shipSpeedUpgradeBtn; if (sub) { var bx = sub.x, by = sub.y; if (x > bx - 180 && x < bx + 180 && y > by - 50 && y < by + 50) { var level = window.shipSpeedUpgradeLevel || 0; var cost = Math.round((120 + level * 60) * 1.9); if (playerCoins >= cost) { playerCoins -= cost; level++; window.shipSpeedUpgradeLevel = level; // Each level increases speed by 10% (multiplicative) ship.speed = Math.round(ship.speed * Math.pow(1.1, 1) * 100) / 100; sub.setText("Alındı! +" + level * 10 + "%"); sub.fill = 0x00ffcc; LK.effects.flashObject(ship, 0x00ffff, 400); updateUI(); saveProgress(); } else { sub.setText("Yetersiz coin!"); sub.fill = 0xff4444; } return; } } // Close button var cb = window.shipUpgradeCloseBtn; if (cb) { var bx = cb.x, by = cb.y; if (x > bx - 120 && x < bx + 120 && y > by - 50 && y < by + 50) { // Remove all panel elements if (window.shipUpgradePanel && window.shipUpgradePanel.parent) window.shipUpgradePanel.parent.removeChild(window.shipUpgradePanel); if (window.shipUpgradeTitle && window.shipUpgradeTitle.parent) window.shipUpgradeTitle.parent.removeChild(window.shipUpgradeTitle); if (window.shipUpgradeBtn1 && window.shipUpgradeBtn1.parent) window.shipUpgradeBtn1.parent.removeChild(window.shipUpgradeBtn1); if (window.shipUpgradeBtn1x2 && window.shipUpgradeBtn1x2.parent) window.shipUpgradeBtn1x2.parent.removeChild(window.shipUpgradeBtn1x2); if (window.shipUpgradeBtn2 && window.shipUpgradeBtn2.parent) window.shipUpgradeBtn2.parent.removeChild(window.shipUpgradeBtn2); if (window.shipUpgradeBtn2x2 && window.shipUpgradeBtn2x2.parent) window.shipUpgradeBtn2x2.parent.removeChild(window.shipUpgradeBtn2x2); if (window.shipUpgradeBtn3 && window.shipUpgradeBtn3.parent) window.shipUpgradeBtn3.parent.removeChild(window.shipUpgradeBtn3); if (window.shipUpgradeBtn3x2 && window.shipUpgradeBtn3x2.parent) window.shipUpgradeBtn3x2.parent.removeChild(window.shipUpgradeBtn3x2); if (window.shipBuyHealthBtn && window.shipBuyHealthBtn.parent) window.shipBuyHealthBtn.parent.removeChild(window.shipBuyHealthBtn); if (window.shipSpeedUpgradeBtn && window.shipSpeedUpgradeBtn.parent) window.shipSpeedUpgradeBtn.parent.removeChild(window.shipSpeedUpgradeBtn); if (window.shipUpgradeCloseBtn && window.shipUpgradeCloseBtn.parent) window.shipUpgradeCloseBtn.parent.removeChild(window.shipUpgradeCloseBtn); // Hide all upgrade panel texts window.shipUpgradePanel = null; window.shipUpgradeTitle = null; window.shipUpgradeBtn1 = null; window.shipUpgradeBtn1x2 = null; window.shipUpgradeBtn2 = null; window.shipUpgradeBtn2x2 = null; window.shipUpgradeBtn3 = null; window.shipUpgradeBtn3x2 = null; window.shipBuyHealthBtn = null; window.shipSpeedUpgradeBtn = null; window.shipUpgradeCloseBtn = null; return; } } } // --- Handle Accept/Reject quest button taps --- if (game._questDecisionAcceptBtn && game._questDecisionAcceptBtn.parent) { var btn = game._questDecisionAcceptBtn; var bx = btn.x, by = btn.y; // Button is about 180x80 px if (x > bx - 90 && x < bx + 90 && y > by - 40 && y < by + 40) { // Accept quest var npc = btn._questNPC; if (npc) { // Defend quest özel: yardım kabul edildi if (npc.questType === 'defend') { npc._defendHelpAccepted = true; // Show floating label for accepted var acceptLabel = new Text2("Yardım kabul edildi!", { size: 36, fill: 0x00ff99, align: "center" }); acceptLabel.anchor.set(0.5, 0.5); acceptLabel.x = npc.x; acceptLabel.y = npc.y + 110; game.addChild(acceptLabel); npc._npcInteractionLabel = acceptLabel; npc._npcInteractionLabelExpire = LK.ticks + 120; npc.pauseUntil = LK.ticks + 120; npc._npcText && npc._npcText.parent && npc._npcText.parent.removeChild(npc._npcText); npc._npcText = new Text2(npc.rpgName + ": Teşekkürler! Beni korsanlardan koru!", { size: 32, fill: 0x00ffcc, align: "center" }); npc._npcText.anchor.set(0.5, 1); npc._npcText.x = npc.x; npc._npcText.y = npc.y - 70; game.addChild(npc._npcText); } else { // Mark quest as accepted (progress 1 means started) npc.questProgress = 1; // Show NPC response var acceptLabel = new Text2("Görev kabul edildi!", { size: 36, fill: 0x00ff99, align: "center" }); acceptLabel.anchor.set(0.5, 0.5); acceptLabel.x = npc.x; acceptLabel.y = npc.y + 110; game.addChild(acceptLabel); npc._npcInteractionLabel = acceptLabel; npc._npcInteractionLabelExpire = LK.ticks + 120; npc.pauseUntil = LK.ticks + 120; npc._npcText && npc._npcText.parent && npc._npcText.parent.removeChild(npc._npcText); npc._npcText = new Text2(npc.rpgName + ": Harika! Görev başladı.", { size: 32, fill: 0x00ffcc, align: "center" }); npc._npcText.anchor.set(0.5, 1); npc._npcText.x = npc.x; npc._npcText.y = npc.y - 70; game.addChild(npc._npcText); } // Remove quest panel if (npc._questDecisionPanel && npc._questDecisionPanel.parent) npc._questDecisionPanel.parent.removeChild(npc._questDecisionPanel); if (npc._questDecisionText && npc._questDecisionText.parent) npc._questDecisionText.parent.removeChild(npc._questDecisionText); if (npc._questDecisionAcceptBtn && npc._questDecisionAcceptBtn.parent) npc._questDecisionAcceptBtn.parent.removeChild(npc._questDecisionAcceptBtn); if (npc._questDecisionRejectBtn && npc._questDecisionRejectBtn.parent) npc._questDecisionRejectBtn.parent.removeChild(npc._questDecisionRejectBtn); npc._questDecisionPanel = null; npc._questDecisionText = null; npc._questDecisionAcceptBtn = null; npc._questDecisionRejectBtn = null; game._questDecisionPanel = null; game._questDecisionAcceptBtn = null; game._questDecisionRejectBtn = null; game._questDecisionText = null; game._questDecisionNPC = null; } return; } } if (game._questDecisionRejectBtn && game._questDecisionRejectBtn.parent) { var btn = game._questDecisionRejectBtn; var bx = btn.x, by = btn.y; if (x > bx - 90 && x < bx + 90 && y > by - 40 && y < by + 40) { // Reject quest var npc = btn._questNPC; if (npc) { if (npc.questType === 'defend') { npc._defendHelpAccepted = false; // Show floating label for rejected var rejectLabel = new Text2("Yardım edilmedi.", { size: 36, fill: 0xff4444, align: "center" }); rejectLabel.anchor.set(0.5, 0.5); rejectLabel.x = npc.x; rejectLabel.y = npc.y + 110; game.addChild(rejectLabel); npc._npcInteractionLabel = rejectLabel; npc._npcInteractionLabelExpire = LK.ticks + 120; npc.pauseUntil = LK.ticks + 120; npc._npcText && npc._npcText.parent && npc._npcText.parent.removeChild(npc._npcText); npc._npcText = new Text2(npc.rpgName + ": Anlaşıldı, kendi başıma savaşacağım!", { size: 32, fill: 0x00ffcc, align: "center" }); npc._npcText.anchor.set(0.5, 1); npc._npcText.x = npc.x; npc._npcText.y = npc.y - 70; game.addChild(npc._npcText); } else { // Mark quest as inactive npc.questActive = false; // Show floating label for rejected var rejectLabel = new Text2("Görev reddedildi.", { size: 36, fill: 0xff4444, align: "center" }); rejectLabel.anchor.set(0.5, 0.5); rejectLabel.x = npc.x; rejectLabel.y = npc.y + 110; game.addChild(rejectLabel); npc._npcInteractionLabel = rejectLabel; npc._npcInteractionLabelExpire = LK.ticks + 120; npc.pauseUntil = LK.ticks + 120; npc._npcText && npc._npcText.parent && npc._npcText.parent.removeChild(npc._npcText); npc._npcText = new Text2(npc.rpgName + ": Belki başka zaman!", { size: 32, fill: 0x00ffcc, align: "center" }); npc._npcText.anchor.set(0.5, 1); npc._npcText.x = npc.x; npc._npcText.y = npc.y - 70; game.addChild(npc._npcText); } // Remove quest panel if (npc._questDecisionPanel && npc._questDecisionPanel.parent) npc._questDecisionPanel.parent.removeChild(npc._questDecisionPanel); if (npc._questDecisionText && npc._questDecisionText.parent) npc._questDecisionText.parent.removeChild(npc._questDecisionText); if (npc._questDecisionAcceptBtn && npc._questDecisionAcceptBtn.parent) npc._questDecisionAcceptBtn.parent.removeChild(npc._questDecisionAcceptBtn); if (npc._questDecisionRejectBtn && npc._questDecisionRejectBtn.parent) npc._questDecisionRejectBtn.parent.removeChild(npc._questDecisionRejectBtn); npc._questDecisionPanel = null; npc._questDecisionText = null; npc._questDecisionAcceptBtn = null; npc._questDecisionRejectBtn = null; game._questDecisionPanel = null; game._questDecisionAcceptBtn = null; game._questDecisionRejectBtn = null; game._questDecisionText = null; game._questDecisionNPC = null; } return; } } // Check for NPC tap (RPG/adventure/trade) for (var i = 0; i < npcs.length; i++) { var npc = npcs[i]; var dist = Math.sqrt(Math.pow(npc.x - ship.x, 2) + Math.pow(npc.y - ship.y, 2)); if (dist < 180) { game._lastNPCTap = LK.ticks; break; } } // --- Distress event tap detection --- if (window.distressEvent && window.distressEvent.helpBtn && window.distressEvent.ignoreBtn) { game._lastDistressTapTick = LK.ticks; game._lastDistressTapX = x; game._lastDistressTapY = y; } } }; game.move = function (x, y, obj) { if (isDragging) { var dx = x - joystickBase.x; var dy = y - joystickBase.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 100) { dx = dx / distance * 100; dy = dy / distance * 100; } joystickHandle.x = joystickBase.x + dx; joystickHandle.y = joystickBase.y + dy; } }; game.up = function (x, y, obj) { isDragging = false; joystickHandle.x = joystickBase.x; joystickHandle.y = joystickBase.y; }; // Main game loop game.update = function () { // Ship movement var shipDX = 0; var shipDY = 0; if (isDragging) { var dx = joystickHandle.x - joystickBase.x; var dy = joystickHandle.y - joystickBase.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 10) { var effectiveSpeed = ship.speed; shipDX = dx / 100 * effectiveSpeed; shipDY = dy / 100 * effectiveSpeed; ship.rotation = Math.atan2(dy, dx) + Math.PI / 2; } } ship.x += shipDX; ship.y += shipDY; // Track total distance traveled totalDistance += Math.sqrt(shipDX * shipDX + shipDY * shipDY); // Update camera to follow ship movement camera.x += shipDX; camera.y += shipDY; // Move all world objects opposite to ship movement to create camera effect for (var i = 0; i < stars.length; i++) { stars[i].x -= shipDX; stars[i].y -= shipDY; } for (var i = 0; i < npcs.length; i++) { npcs[i].x -= shipDX; npcs[i].y -= shipDY; } for (var i = 0; i < pirates.length; i++) { pirates[i].x -= shipDX; pirates[i].y -= shipDY; } for (var i = 0; i < coins.length; i++) { coins[i].x -= shipDX; coins[i].y -= shipDY; } for (var i = 0; i < resources.length; i++) { resources[i].x -= shipDX; resources[i].y -= shipDY; } for (var i = 0; i < bullets.length; i++) { bullets[i].x -= shipDX; bullets[i].y -= shipDY; } for (var i = 0; i < enemyBullets.length; i++) { enemyBullets[i].x -= shipDX; enemyBullets[i].y -= shipDY; } for (var i = 0; i < asteroids.length; i++) { asteroids[i].x -= shipDX; asteroids[i].y -= shipDY; } for (var i = 0; i < upgradeStations.length; i++) { upgradeStations[i].x -= shipDX; upgradeStations[i].y -= shipDY; } // boostParticles removed (no boost system) for (var i = 0; i < explosions.length; i++) { explosions[i].x -= shipDX; explosions[i].y -= shipDY; } // Auto fire at very close pirates or asteroids // Saldırı mesafesi %10 arttırıldı (200 -> 220) var ATTACK_RANGE = 220; if (LK.ticks - ship.lastFire > ship.fireRate && (pirates.length > 0 || asteroids.length > 0)) { // Find nearest pirate or asteroid within 220 pixels var nearestTarget = null; var nearestDistance = Infinity; var isPirate = false; // Check pirates for (var i = 0; i < pirates.length; i++) { var dist = Math.sqrt(Math.pow(pirates[i].x - ship.x, 2) + Math.pow(pirates[i].y - ship.y, 2)); if (dist < ATTACK_RANGE && dist < nearestDistance) { nearestDistance = dist; nearestTarget = pirates[i]; isPirate = true; } } // Check asteroids for (var i = 0; i < asteroids.length; i++) { var dist = Math.sqrt(Math.pow(asteroids[i].x - ship.x, 2) + Math.pow(asteroids[i].y - ship.y, 2)); if (dist < ATTACK_RANGE && dist < nearestDistance) { nearestDistance = dist; nearestTarget = asteroids[i]; isPirate = false; } } if (nearestTarget) { var bullet = new Bullet(); bullet.x = ship.x; bullet.y = ship.y; var angle = Math.atan2(nearestTarget.y - ship.y, nearestTarget.x - ship.x); bullet.directionX = Math.cos(angle); bullet.directionY = Math.sin(angle); bullet.rotation = angle + Math.PI / 2; bullets.push(bullet); game.addChild(bullet); ship.lastFire = LK.ticks; LK.getSound('shoot').play(); } } // Update bullets for (var i = bullets.length - 1; i >= 0; i--) { var bullet = bullets[i]; if (bullet.x < -50 || bullet.x > 2098 || bullet.y < -50 || bullet.y > 2782) { bullet.destroy(); bullets.splice(i, 1); continue; } // Check collision with pirates for (var j = pirates.length - 1; j >= 0; j--) { if (bullet.intersects(pirates[j])) { pirates[j].takeDamage(bullet.damage); var killedByPlayer = !bullet._npcBullet; var killedByNPC = !!bullet._npcBullet; if (pirates[j].health <= 0) { enemiesKilled++; createExplosion(pirates[j].x, pirates[j].y); // Drop loot var coin = new Coin(); coin.x = pirates[j].x; coin.y = pirates[j].y; coin.value = coin.value * (1 + Math.floor(waveNumber / 3)); coins.push(coin); game.addChild(coin); if (Math.random() < 0.3) { var resource = new Resource(); resource.x = pirates[j].x + (Math.random() - 0.5) * 50; resource.y = pirates[j].y + (Math.random() - 0.5) * 50; resources.push(resource); game.addChild(resource); } // Remove KILL label after 2 seconds if present if (pirates[j]._killLabel) { // If not already expiring, set expire tick if (!pirates[j]._killLabel._expireTick) { pirates[j]._killLabel._expireTick = LK.ticks + 120; } } // Remove KILL label if expired if (pirates[j]._killLabel && pirates[j]._killLabel._expireTick && LK.ticks > pirates[j]._killLabel._expireTick) { if (pirates[j]._killLabel.parent) pirates[j]._killLabel.parent.removeChild(pirates[j]._killLabel); pirates[j]._killLabel = null; } if (killedByPlayer) { // Oyuncu öldürdü: sadece exp kazan var pirateExp = 3 + Math.floor(Math.random() * 3); playerEXP += pirateExp; // Level up if enough EXP while (playerEXP >= expToNext(playerLevel)) { playerEXP -= expToNext(playerLevel); playerLevel++; LK.effects.flashObject(ship, 0x00ffcc, 800); } } else if (killedByNPC) { // NPC öldürdü: yoluna devam etsin, rep/exp yok // Kısa bir etiket göster (isteğe bağlı) var npcLabel = new Text2("NPC KILL", { size: 28, fill: 0xccccff, align: "center" }); npcLabel.anchor.set(0.5, 0.5); npcLabel.x = pirates[j].x; npcLabel.y = pirates[j].y - 80; game.addChild(npcLabel); // Fade out and remove after 700ms LK.setTimeout(function () { if (npcLabel.parent) { npcLabel.parent.removeChild(npcLabel); } }, 700); } // Update UI after EXP gain updateUI(); pirates[j].destroy(); pirates.splice(j, 1); // Check for wave completion if (enemiesKilled >= 10 + waveNumber * 5) { waveNumber++; enemiesKilled = 0; // Spawn upgrade station every 3 waves if (waveNumber % 3 === 0) { spawnUpgradeStation(); } } } bullet.destroy(); bullets.splice(i, 1); LK.getSound('hit').play(); break; } } // --- PLAYER CAN ATTACK NPCs IF FIGHT MODE IS ON --- if (window.npcFightMode) { for (var j = npcs.length - 1; j >= 0; j--) { var npc = npcs[j]; if (bullet.intersects(npc)) { if (typeof npc.health === "undefined") npc.health = 100; npc.health -= bullet.damage; LK.effects.flashObject(npc, 0xff0000, 120); // Floating label for NPC hit var npcHitLabel = new Text2("NPC HIT", { size: 24, fill: 0xff8888, align: "center" }); npcHitLabel.anchor.set(0.5, 0.5); npcHitLabel.x = npc.x; npcHitLabel.y = npc.y - 60; game.addChild(npcHitLabel); LK.setTimeout(function (label) { if (label.parent) label.parent.removeChild(label); }.bind(null, npcHitLabel), 600); // Remove NPC if dead if (npc.health <= 0) { // Floating label for NPC kill var npcKillLabel = new Text2("NPC KILL", { size: 28, fill: 0xccccff, align: "center" }); npcKillLabel.anchor.set(0.5, 0.5); npcKillLabel.x = npc.x; npcKillLabel.y = npc.y - 80; game.addChild(npcKillLabel); LK.setTimeout(function (label) { if (label.parent) label.parent.removeChild(label); }.bind(null, npcKillLabel), 700); // Oyuncu NPC öldürdü: coin kaybı uygula var coinLoss = 10 + Math.floor(Math.random() * 41); // 10-50 arası coin kaybı playerCoins = Math.max(0, playerCoins - coinLoss); // Kısa bir etiket göster var coinLossLabel = new Text2("-" + coinLoss + " coin", { size: 28, fill: 0xff4444, align: "center" }); coinLossLabel.anchor.set(0.5, 0.5); coinLossLabel.x = npc.x; coinLossLabel.y = npc.y - 120; game.addChild(coinLossLabel); LK.setTimeout(function (label) { if (label.parent) label.parent.removeChild(label); }, 900, coinLossLabel); updateUI(); // Remove hostile label if present if (npc._hostileLabel && npc._hostileLabel.parent) { npc._hostileLabel.parent.removeChild(npc._hostileLabel); npc._hostileLabel = null; } // Instantly remove Düşman! label if it exists (defensive, in case above missed) if (npc._hostileLabel && npc._hostileLabel.parent) { npc._hostileLabel.parent.removeChild(npc._hostileLabel); npc._hostileLabel = null; } npc.destroy(); npcs.splice(j, 1); } bullet.destroy(); bullets.splice(i, 1); LK.getSound('hit').play(); break; } } } // Check collision with asteroids for (var j = asteroids.length - 1; j >= 0; j--) { if (bullet.intersects(asteroids[j])) { asteroids[j].takeDamage(bullet.damage); if (asteroids[j].health <= 0) { // Drop multiple resources (reduced by 80%) var dropCount = Math.max(1, Math.floor(asteroids[j].resources * 0.2)); for (var k = 0; k < dropCount; k++) { var resource = new Resource(); resource.x = asteroids[j].x + (Math.random() - 0.5) * 100; resource.y = asteroids[j].y + (Math.random() - 0.5) * 100; resource.amount = Math.floor(Math.random() * 3) + 1; resources.push(resource); game.addChild(resource); } createExplosion(asteroids[j].x, asteroids[j].y); asteroids[j].destroy(); asteroids.splice(j, 1); } bullet.destroy(); bullets.splice(i, 1); LK.getSound('hit').play(); break; } } } // Update enemy bullets for (var i = enemyBullets.length - 1; i >= 0; i--) { var bullet = enemyBullets[i]; if (bullet.x < -50 || bullet.x > 2098 || bullet.y < -50 || bullet.y > 2782) { bullet.destroy(); enemyBullets.splice(i, 1); continue; } if (bullet.intersects(ship)) { ship.takeDamage(bullet.damage); updateUI(); bullet.destroy(); enemyBullets.splice(i, 1); LK.getSound('hit').play(); continue; } // --- NEW: Pirate bullets can hit NPCs --- for (var n = npcs.length - 1; n >= 0; n--) { var npc = npcs[n]; if (bullet.intersects(npc)) { // Damage NPC if (typeof npc.health === "undefined") npc.health = 100; npc.health -= bullet.damage; LK.effects.flashObject(npc, 0xff0000, 120); // Floating label for NPC hit (optional) var npcHitLabel = new Text2("NPC HIT", { size: 24, fill: 0xff8888, align: "center" }); npcHitLabel.anchor.set(0.5, 0.5); npcHitLabel.x = npc.x; npcHitLabel.y = npc.y - 60; game.addChild(npcHitLabel); LK.setTimeout(function (label) { if (label.parent) label.parent.removeChild(label); }.bind(null, npcHitLabel), 600); // Remove NPC if dead if (npc.health <= 0) { // Floating label for NPC kill var npcKillLabel = new Text2("NPC KILL", { size: 28, fill: 0xccccff, align: "center" }); npcKillLabel.anchor.set(0.5, 0.5); npcKillLabel.x = npc.x; npcKillLabel.y = npc.y - 80; game.addChild(npcKillLabel); LK.setTimeout(function (label) { if (label.parent) label.parent.removeChild(label); }.bind(null, npcKillLabel), 700); // Remove hostile label if present if (npc._hostileLabel && npc._hostileLabel.parent) { npc._hostileLabel.parent.removeChild(npc._hostileLabel); npc._hostileLabel = null; } // Remove NPC from world npc.destroy(); npcs.splice(n, 1); } bullet.destroy(); enemyBullets.splice(i, 1); LK.getSound('hit').play(); break; } } } // Update pirates for (var i = 0; i < pirates.length; i++) { var pirate = pirates[i]; if (pirate._healthBar && pirate._healthBar.update) pirate._healthBar.update(); // --- Pirate AI: Always attack the nearest target (NPC or player) --- var nearestTarget = null; var minDist = Infinity; // Find nearest NPC for (var n = 0; n < npcs.length; n++) { var npc = npcs[n]; var distToNPC = Math.sqrt(Math.pow(npc.x - pirate.x, 2) + Math.pow(npc.y - pirate.y, 2)); if (distToNPC < minDist) { minDist = distToNPC; nearestTarget = npc; } } // Compare with player distance var distToPlayer = Math.sqrt(Math.pow(ship.x - pirate.x, 2) + Math.pow(ship.y - pirate.y, 2)); if (distToPlayer < minDist) { minDist = distToPlayer; nearestTarget = ship; } // If there is a target, move and attack if (nearestTarget && minDist < 600) { // --- 5% mesafe kuralı: hedefe %5 mesafe bırak, iç içe girme --- var targetRadius = 40; // Varsayılan hedef yarıçapı (NPC/ship/pirate boyutu) if (nearestTarget._healthBar && nearestTarget._healthBar._width) { targetRadius = Math.max(targetRadius, nearestTarget._healthBar._width / 2); } var selfRadius = 35; // Korsan yarıçapı if (pirate._healthBar && pirate._healthBar._width) { selfRadius = Math.max(selfRadius, pirate._healthBar._width / 2); } var minBuffer = (minDist + selfRadius + targetRadius) * 0.05; // %5 buffer var minAllowedDist = selfRadius + targetRadius + minBuffer; var angle = Math.atan2(nearestTarget.y - pirate.y, nearestTarget.x - pirate.x); // Sadece minAllowedDist'ten uzaktaysa yaklaş if (minDist > minAllowedDist) { var moveDist = Math.min(pirate.speed, minDist - minAllowedDist); pirate.x += Math.cos(angle) * moveDist; pirate.y += Math.sin(angle) * moveDist; pirate.rotation = angle + Math.PI / 2; } else { // Hedefe çok yaklaştıysa sadece dön, hareket etme pirate.rotation = angle + Math.PI / 2; } // Shoot at target if (LK.ticks - pirate.lastFire > pirate.fireRate) { var bullet = new EnemyBullet(); bullet.x = pirate.x; bullet.y = pirate.y; bullet.directionX = Math.cos(angle); bullet.directionY = Math.sin(angle); bullet.rotation = angle + Math.PI / 2; bullet._pirateBullet = true; enemyBullets.push(bullet); game.addChild(bullet); pirate.lastFire = LK.ticks; } } else { // Wander randomly pirate.x += Math.cos(pirate.moveAngle) * pirate.speed * 0.5; pirate.y += Math.sin(pirate.moveAngle) * pirate.speed * 0.5; } // Remove pirates that are too far away var dist = Math.sqrt(Math.pow(ship.x - pirate.x, 2) + Math.pow(ship.y - pirate.y, 2)); if (dist > 2000) { pirate.destroy(); pirates.splice(i, 1); i--; } } // Update NPCs for (var i = npcs.length - 1; i >= 0; i--) { var npc = npcs[i]; if (npc._healthBar && npc._healthBar.update) npc._healthBar.update(); // Remove NPCs that are too far away var dist = Math.sqrt(Math.pow(npc.x - ship.x, 2) + Math.pow(npc.y - ship.y, 2)); if (dist > 2500) { npc.destroy(); npcs.splice(i, 1); continue; } // Remove any floating text if player is not close if (npc._npcText && npc._npcText.parent) { npc._npcText.parent.removeChild(npc._npcText); npc._npcText = null; } // --- NPC ATTITUDE: Rep sistemi kaldırıldı, sadece NPC Saldırı butonuna göre saldırı --- // Eğer NPC Saldırı aktifse, her durumda NPC'ler oyuncuya saldırır var npcHostile = false; if (window.npcSaldiriBtn && window.npcSaldiriBtn._active) { npcHostile = true; } else { npcHostile = false; } // --- NPC AI: Always attack the nearest target (pirate or player) --- // If NPC Saldırı is PASİF, NPCs never attack the player var nearestTarget = null; var minDist = Infinity; // Find nearest pirate for (var j = 0; j < pirates.length; j++) { var p = pirates[j]; if (p._destroyed) continue; var d = Math.sqrt(Math.pow(p.x - npc.x, 2) + Math.pow(p.y - npc.y, 2)); if (d < minDist) { minDist = d; nearestTarget = p; } } // Compare with player distance only if NPC Saldırı is AKTİF var npcSaldiriActive = window.npcSaldiriBtn && window.npcSaldiriBtn._active; if (npcSaldiriActive) { var distToPlayer = Math.sqrt(Math.pow(ship.x - npc.x, 2) + Math.pow(ship.y - npc.y, 2)); if (distToPlayer < minDist) { minDist = distToPlayer; nearestTarget = ship; } } // If there is a target, move and attack if (nearestTarget && minDist < 600) { // --- 5% mesafe kuralı: hedefe %5 mesafe bırak, iç içe girme --- var targetRadius = 40; if (nearestTarget._healthBar && nearestTarget._healthBar._width) { targetRadius = Math.max(targetRadius, nearestTarget._healthBar._width / 2); } var selfRadius = 30; if (npc._healthBar && npc._healthBar._width) { selfRadius = Math.max(selfRadius, npc._healthBar._width / 2); } var minBuffer = (minDist + selfRadius + targetRadius) * 0.05; var minAllowedDist = selfRadius + targetRadius + minBuffer; var dx = nearestTarget.x - npc.x; var dy = nearestTarget.y - npc.y; var d = Math.sqrt(dx * dx + dy * dy); if (d > minAllowedDist) { var moveDist = Math.min(npc.moveSpeed * 1.2, d - minAllowedDist); npc.x += dx / d * moveDist; npc.y += dy / d * moveDist; } // Shoot at target (use NPC bullet fire rate) if (typeof npc._aiAttackTimer === "undefined") npc._aiAttackTimer = 0; npc._aiAttackTimer++; // Use the same fire rate as pirates (EnemyBullet speed) var npcFireRate = 8; if (typeof npc.fireRate === "number") { npcFireRate = npc.fireRate; } else { npcFireRate = 40; } if (d < 300 && npc._aiAttackTimer > npcFireRate) { var bullet; var angle = Math.atan2(nearestTarget.y - npc.y, nearestTarget.x - npc.x); if (nearestTarget === ship) { bullet = new EnemyBullet(); bullet._npcBullet = true; } else { bullet = new Bullet(); bullet._npcBullet = true; } bullet.x = npc.x; bullet.y = npc.y; bullet.directionX = Math.cos(angle); bullet.directionY = Math.sin(angle); bullet.rotation = angle + Math.PI / 2; if (nearestTarget === ship) { enemyBullets.push(bullet); } else { bullets.push(bullet); } game.addChild(bullet); npc._aiAttackTimer = 0; } // Show angry label above NPC if attacking player if (nearestTarget === ship) { if (!npc._hostileLabel || !npc._hostileLabel.parent) { npc._hostileLabel = new Text2("Düşman!", { size: 32, fill: 0xff4444, align: "center" }); npc._hostileLabel.anchor.set(0.5, 0.5); npc._hostileLabel.x = npc.x; npc._hostileLabel.y = npc.y - 80; npc._hostileLabel.alpha = 1; game.addChild(npc._hostileLabel); } if (npc._hostileLabel) { npc._hostileLabel.x = npc.x; npc._hostileLabel.y = npc.y - 80; npc._hostileLabel.alpha = 1; npc._hostileLabel._expireTick = LK.ticks + 60; // 1 second } if (npc._hostileLabel && npc._hostileLabel._expireTick && LK.ticks > npc._hostileLabel._expireTick) { if (npc._hostileLabel.parent) npc._hostileLabel.parent.removeChild(npc._hostileLabel); npc._hostileLabel = null; } else if (npc._hostileLabel && npc._hostileLabel._expireTick) { var fadeStart = npc._hostileLabel._expireTick - 20; if (LK.ticks > fadeStart) { npc._hostileLabel.alpha = Math.max(0, (npc._hostileLabel._expireTick - LK.ticks) / 20); } else { npc._hostileLabel.alpha = 1; } } } else { // Remove hostile label if present if (npc._hostileLabel && npc._hostileLabel.parent) { npc._hostileLabel.parent.removeChild(npc._hostileLabel); npc._hostileLabel = null; } } } else { // Remove hostile label if present if (npc._hostileLabel && npc._hostileLabel.parent) { npc._hostileLabel.parent.removeChild(npc._hostileLabel); npc._hostileLabel = null; } } } // Update asteroids for (var i = asteroids.length - 1; i >= 0; i--) { var asteroid = asteroids[i]; if (asteroid._healthBar && asteroid._healthBar.update) asteroid._healthBar.update(); var dist = Math.sqrt(Math.pow(asteroid.x - ship.x, 2) + Math.pow(asteroid.y - ship.y, 2)); if (dist > 2500) { asteroid.destroy(); asteroids.splice(i, 1); } } // Update explosion particles for (var i = explosions.length - 1; i >= 0; i--) { var particle = explosions[i]; particle.x += particle.vx; particle.y += particle.vy; particle.vx *= 0.9; particle.vy *= 0.9; particle.life--; particle.alpha = particle.life / 30; particle.scaleX = particle.scaleY = 1 + (30 - particle.life) / 10; if (particle.life <= 0) { particle.destroy(); explosions.splice(i, 1); } } // Collect items for (var i = coins.length - 1; i >= 0; i--) { if (coins[i].intersects(ship)) { playerCoins += coins[i].value; coins[i].destroy(); coins.splice(i, 1); LK.getSound('collect').play(); updateUI(); saveProgress(); } } for (var i = resources.length - 1; i >= 0; i--) { if (resources[i].intersects(ship)) { // 10 tip için index bul var resourceTypes = ['metal', 'energy', 'crystal', 'gas', 'ice', 'uranium', 'silicon', 'carbon', 'plasma', 'antimatter']; var idx = resourceTypes.indexOf(resources[i].type); if (idx >= 0) { playerResources[idx] += resources[i].amount; } resources[i].destroy(); resources.splice(i, 1); LK.getSound('collect').play(); updateUI(); saveProgress(); } } // Update stars for (var i = stars.length - 1; i >= 0; i--) { var dist = Math.sqrt(Math.pow(stars[i].x - ship.x, 2) + Math.pow(stars[i].y - ship.y, 2)); if (dist > 2000) { stars[i].destroy(); stars.splice(i, 1); } } // Spawn entities (star spawn frequency is now random interval) if (typeof window._nextStarSpawnTick === "undefined") { window._nextStarSpawnTick = LK.ticks + Math.floor(20 + Math.random() * 60); // 20-80 ticks } if (LK.ticks >= window._nextStarSpawnTick) { spawnStar(true); window._nextStarSpawnTick = LK.ticks + Math.floor(20 + Math.random() * 60); // 20-80 ticks } // Spawn pirates and NPCs at intervals if (pirates.length < 6 && Math.random() < 0.3) { spawnPirate(); } if (npcs.length < 4 && Math.random() < 0.2) { spawnNPC(); } // Spawn Suçlu at rare intervals (max 2 at a time) if (suclus.length < 2 && Math.random() < 0.04) { var suclu = new Suclu(); // Spawn from edges of visible area var edge = Math.floor(Math.random() * 4); switch (edge) { case 0: // Top suclu.x = ship.x + (Math.random() - 0.5) * 2000; suclu.y = ship.y - 1700; break; case 1: // Right suclu.x = ship.x + 1700; suclu.y = ship.y + (Math.random() - 0.5) * 2000; break; case 2: // Bottom suclu.x = ship.x + (Math.random() - 0.5) * 2000; suclu.y = ship.y + 1700; break; case 3: // Left suclu.x = ship.x - 1700; suclu.y = ship.y + (Math.random() - 0.5) * 2000; break; } suclus.push(suclu); game.addChild(suclu); } // --- ASTEROID SYSTEM RESTORED --- // Spawn asteroids if less than 6 in the world (20% reduction from 8) if (asteroids.length < 6 && Math.random() < 0.025) { spawnAsteroid(); } // Update score LK.setScore(playerCoins + questsCompleted * 100 + enemiesKilled * 10 + Math.floor(totalDistance / 100)); if (ship._healthBar && ship._healthBar.update) ship._healthBar.update(); updateUI(); // --- AUTO-REPAIR PANEL WHEN HEALTH IS LOW OR HEALTH BAR TAPPED --- // Show repair panel if health < 100% and not dead, and not already shown if (!window.repairPanel && ship.health < ship.maxHealth && ship.health > 0 && window._showRepairPanel && (!window._repairPanelSuppressUntil || LK.ticks > window._repairPanelSuppressUntil)) { // Calculate how much health will be restored var healthToRestore = ship.maxHealth - ship.health; // Proportional cost scaling // Base costs for full repair: 90 coins, 6 metal, 6 energy (for 60 health missing) // Scale linearly with health to restore, but clamp minimums var baseFullRepairHealth = 60; var baseCoinCost = 90 * 2; var baseMetalCost = 6 * 2; var baseEnergyCost = 6 * 2; var repairCostCoins = Math.max(30, Math.round(baseCoinCost * (healthToRestore / baseFullRepairHealth))); var repairCostMetal = Math.max(2, Math.round(baseMetalCost * (healthToRestore / baseFullRepairHealth))); var repairCostEnergy = Math.max(2, Math.round(baseEnergyCost * (healthToRestore / baseFullRepairHealth))); // Panel background // --- DYNAMIC REPAIR PANEL SIZE BASED ON TEXT --- var repairTextStr = "Gemi hasarlı! Tamir: " + repairCostCoins + " coin, " + repairCostMetal + " metal, " + repairCostEnergy + " enerji"; var repairPanelFontSize = 38; var repairPanelWidth = Math.max(700, repairTextStr.length * repairPanelFontSize * 0.32); var repairPanelHeight = 180 + repairPanelFontSize * 1.5; // text + buttons var panel = LK.getAsset('resource', { anchorX: 0.5, anchorY: 0.5, x: ship.x, y: ship.y - 220, scaleX: repairPanelWidth / 40, scaleY: repairPanelHeight / 40, tint: 0x224444 }); // Repair text var repairText = new Text2("Gemi hasarlı! Tamir: " + repairCostCoins + " coin, " + repairCostMetal + " metal, " + repairCostEnergy + " enerji", { size: 38, fill: 0xffffff, align: "center" }); repairText.anchor.set(0.5, 0.5); repairText.x = ship.x; repairText.y = ship.y - 240; // Repair button var repairBtn = new Text2("Tamir Et", { size: 44, fill: 0x00ff99, align: "center" }); repairBtn.anchor.set(0.5, 0.5); repairBtn.x = ship.x - 100; repairBtn.y = ship.y - 160; // Cancel button var cancelBtn = new Text2("Kapat", { size: 44, fill: 0xff4444, align: "center" }); cancelBtn.anchor.set(0.5, 0.5); cancelBtn.x = ship.x + 100; cancelBtn.y = ship.y - 160; // Add to game game.addChild(panel); game.addChild(repairText); game.addChild(repairBtn); game.addChild(cancelBtn); // Store references for tap logic and cleanup window.repairPanel = panel; window.repairText = repairText; window.repairBtn = repairBtn; window.cancelRepairBtn = cancelBtn; repairBtn._isRepairBtn = true; cancelBtn._isCancelRepairBtn = true; repairBtn._repairCostCoins = repairCostCoins; repairBtn._repairCostMetal = repairCostMetal; repairBtn._repairCostEnergy = repairCostEnergy; window._showRepairPanel = false; // Reset flag window._repairPanelSuppressUntil = null; // Reset suppression when panel is shown } else if (window.repairPanel && ship.health >= ship.maxHealth * 0.7) { // Remove repair panel if health is restored if (window.repairPanel.parent) window.repairPanel.parent.removeChild(window.repairPanel); if (window.repairText && window.repairText.parent) window.repairText.parent.removeChild(window.repairText); if (window.repairBtn && window.repairBtn.parent) window.repairBtn.parent.removeChild(window.repairBtn); if (window.cancelRepairBtn && window.cancelRepairBtn.parent) window.cancelRepairBtn.parent.removeChild(window.cancelRepairBtn); window.repairPanel = null; window.repairText = null; window.repairBtn = null; window.cancelRepairBtn = null; window._showRepairPanel = false; } // If health < 50% and not dead, auto-show repair panel (legacy behavior) if (!window.repairPanel && ship.health < ship.maxHealth * 0.5 && ship.health > 0) { window._showRepairPanel = true; } // --- GAME TIME UPDATE --- // Calculate elapsed time in seconds var elapsedTicks = LK.ticks - gameStartTick; var elapsedSeconds = Math.floor(elapsedTicks / 60); var minutes = Math.floor(elapsedSeconds / 60); var seconds = elapsedSeconds % 60; if (typeof gameTimeText !== "undefined") { // Format as mm:ss var timeStr = "Game Time: " + minutes + ":" + (seconds < 10 ? "0" : "") + seconds; gameTimeText.setText(timeStr); // Always keep gameTimeText to the right of coinText gameTimeText.x = coinText.x + coinText.width + 40; gameTimeText.y = coinText.y; } // --- Synchronize LK.ticks with real game time --- // This ensures all time-based systems use real elapsed time, not just frame count LK.ticks = gameStartTick + Math.floor((Date.now() - (window._gameStartRealTime || (window._gameStartRealTime = Date.now()))) / (1000 / 60)); // Update coordinateText with current ship coordinates (rounded) in real time to the left of waveText if (typeof coordinateText !== "undefined" && ship && typeof waveText !== "undefined") { // Show the actual current coordinates of the ship coordinateText.setText('X: ' + Math.round(ship.x) + ' Y: ' + Math.round(ship.y)); // Always keep coordinateText to the left of waveText, and keep size 30% smaller than expText coordinateText.size = Math.round(expText.size * 0.7); coordinateText.x = waveText.x - waveText.width - 30; coordinateText.y = waveText.y + waveText.height / 2; } // --- QUEST TARGET ARROW INDICATOR --- // Only one arrow at a time, create if needed if (!window.questArrow) { // Use a yellow triangle as arrow var arrow = LK.getAsset('bullet', { anchorX: 0.5, anchorY: 0.5, scaleX: 2.5, scaleY: 1.2, tint: 0xffff00, alpha: 0.85 }); arrow.visible = false; window.questArrow = arrow; game.addChild(arrow); } var showArrow = false; var arrowX = 0, arrowY = 0, arrowRot = 0; var questTarget = null; var minDist = Infinity; // Find the nearest active coordinate-based quest target for (var i = 0; i < npcs.length; i++) { var npc = npcs[i]; if (!npc.questActive || !npc.questTarget) continue; // Only for coordinate-based quests if (npc.questType === 'explore' || npc.questType === 'delivery' || npc.questType === 'escort' || npc.questType === 'hunt') { // For hunt, questTarget can be a pirate, otherwise it's {x, y} var tx, ty; if (npc.questType === 'hunt' && npc.questTarget && npc.questTarget.x !== undefined && npc.questTarget.y !== undefined && !npc.questTarget._destroyed) { tx = npc.questTarget.x; ty = npc.questTarget.y; } else if (npc.questTarget.x !== undefined && npc.questTarget.y !== undefined) { tx = npc.questTarget.x; ty = npc.questTarget.y; } if (typeof tx === "number" && typeof ty === "number") { var dist = Math.sqrt(Math.pow(tx - ship.x, 2) + Math.pow(ty - ship.y, 2)); if (dist > 120 && dist < minDist) { // Only show if not already at target minDist = dist; questTarget = { x: tx, y: ty }; } } } } // --- Derelict ship arrow logic --- if (!questTarget && window.derelictShip && window.derelictShip.x !== undefined && window.derelictShip.y !== undefined) { var d = window.derelictShip; var dist = Math.sqrt(Math.pow(d.x - ship.x, 2) + Math.pow(d.y - ship.y, 2)); if (dist > 120 && dist < 3000) { questTarget = { x: d.x, y: d.y }; } } if (questTarget) { // Project questTarget to screen edge var dx = questTarget.x - ship.x; var dy = questTarget.y - ship.y; var angle = Math.atan2(dy, dx); // Screen center in game coordinates var screenW = 2048, screenH = 2732; var margin = 90; // keep arrow inside screen var cx = screenW / 2, cy = screenH / 2; // Find intersection with screen edge var ex = cx + Math.cos(angle) * (Math.min(cx, cy) - margin); var ey = cy + Math.sin(angle) * (Math.min(cx, cy) - margin); // Clamp to screen bounds ex = Math.max(margin, Math.min(screenW - margin, ex)); ey = Math.max(margin, Math.min(screenH - margin, ey)); // Don't show if target is on screen (within 40% of screen from center) if (Math.abs(dx) > screenW * 0.2 || Math.abs(dy) > screenH * 0.2) { showArrow = true; arrowX = ex; arrowY = ey; arrowRot = angle + Math.PI / 2; } } if (window.questArrow) { window.questArrow.visible = showArrow; if (showArrow) { window.questArrow.x = arrowX; window.questArrow.y = arrowY; window.questArrow.rotation = arrowRot; window.questArrow.alpha = 0.85 + Math.sin(LK.ticks * 0.1) * 0.15; window.questArrow.scaleX = 2.5 + Math.sin(LK.ticks * 0.07) * 0.2; window.questArrow.scaleY = 1.2 + Math.cos(LK.ticks * 0.09) * 0.1; window.questArrow.zIndex = 9999; } } // --- Remaining Distance Label for Quest/Event Target --- // Only one label at a time, create if needed if (!window.questDistanceLabel) { var questDistanceLabel = new Text2('', { size: Math.round(unifiedFontSize * 0.9), fill: 0xffffff, align: "center" }); questDistanceLabel.anchor.set(0.5, 0.5); questDistanceLabel.visible = false; window.questDistanceLabel = questDistanceLabel; game.addChild(questDistanceLabel); } var showDistanceLabel = false; var labelX = 0, labelY = 0, labelText = ''; if (questTarget) { // Calculate distance var distToTarget = Math.sqrt(Math.pow(questTarget.x - ship.x, 2) + Math.pow(questTarget.y - ship.y, 2)); // Only show if not already at target and not on screen if (showArrow && distToTarget > 120) { showDistanceLabel = true; // Place label near the arrow, but offset further outwards var labelOffset = 70; labelX = arrowX + Math.cos(arrowRot - Math.PI / 2) * labelOffset; labelY = arrowY + Math.sin(arrowRot - Math.PI / 2) * labelOffset; // Show in km if >1000, else in px if (distToTarget >= 1000) { labelText = Math.round(distToTarget / 10) / 100 + "k px"; } else { labelText = Math.round(distToTarget) + " px"; } // If quest is from an NPC, show a short label for (var i = 0; i < npcs.length; i++) { var npc = npcs[i]; if (npc.questActive && npc.questTarget && (npc.questType === 'explore' || npc.questType === 'delivery' || npc.questType === 'escort') && npc.questTarget.x === questTarget.x && npc.questTarget.y === questTarget.y) { if (npc.questType === 'explore') labelText = "Keşif: " + labelText;else if (npc.questType === 'delivery') labelText = "Teslimat: " + labelText;else if (npc.questType === 'escort') labelText = "Eşlik: " + labelText; break; } if (npc.questActive && npc.questType === 'hunt' && npc.questTarget && npc.questTarget.x === questTarget.x && npc.questTarget.y === questTarget.y) { labelText = "Av: " + labelText; break; } } } } // Derelict ship distance if (!showDistanceLabel && window.derelictShip && window.derelictShip.x !== undefined && window.derelictShip.y !== undefined) { var d = window.derelictShip; var dist = Math.sqrt(Math.pow(d.x - ship.x, 2) + Math.pow(d.y - ship.y, 2)); if (dist > 120 && dist < 3000 && window.questArrow && window.questArrow.visible) { showDistanceLabel = true; var labelOffset = 70; labelX = window.questArrow.x + Math.cos(window.questArrow.rotation - Math.PI / 2) * labelOffset; labelY = window.questArrow.y + Math.sin(window.questArrow.rotation - Math.PI / 2) * labelOffset; labelText = "Gemi: " + (dist >= 1000 ? Math.round(dist / 10) / 100 + "k px" : Math.round(dist) + " px"); } } // Distress event distance if (!showDistanceLabel && window.distressEvent && window.distressEvent.x !== undefined && window.distressEvent.y !== undefined) { var e = window.distressEvent; var dist = Math.sqrt(Math.pow(e.x - ship.x, 2) + Math.pow(e.y - ship.y, 2)); if (dist > 120 && dist < 3000 && window.questArrow && window.questArrow.visible) { showDistanceLabel = true; var labelOffset = 70; labelX = window.questArrow.x + Math.cos(window.questArrow.rotation - Math.PI / 2) * labelOffset; labelY = window.questArrow.y + Math.sin(window.questArrow.rotation - Math.PI / 2) * labelOffset; labelText = "İmdat: " + (dist >= 1000 ? Math.round(dist / 10) / 100 + "k px" : Math.round(dist) + " px"); } } if (window.questDistanceLabel) { window.questDistanceLabel.visible = showDistanceLabel; if (showDistanceLabel) { window.questDistanceLabel.x = labelX; window.questDistanceLabel.y = labelY; window.questDistanceLabel.setText(labelText); window.questDistanceLabel.alpha = 0.9 + Math.sin(LK.ticks * 0.1) * 0.1; window.questDistanceLabel.size = Math.round(unifiedFontSize * 0.9); window.questDistanceLabel.zIndex = 9999; } } }; // Defensive: Override LK.showGameOver to do nothing except for Reset button (function () { var origShowGameOver = LK.showGameOver; LK.showGameOver = function () { // Only allow Game Over if called from Reset button (by checking stack) var err = new Error(); var stack = (err.stack || "").toString(); if (stack.indexOf("game._resetBtn") !== -1) { origShowGameOver.apply(LK, arguments); } // Otherwise, do nothing (no Game Over on death) }; })();
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Asteroid = Container.expand(function () {
var self = Container.call(this);
var asteroidGraphics = self.attachAsset('resource', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0x8B4513,
scaleX: 2,
scaleY: 2
});
self.health = 50;
self.resources = Math.floor(Math.random() * 10) + 5;
self.vx = (Math.random() - 0.5) * 0.5;
self.vy = (Math.random() - 0.5) * 0.5;
self.rotationSpeed = (Math.random() - 0.5) * 0.02;
self.takeDamage = function (amount) {
self.health -= amount;
LK.effects.flashObject(self, 0xffffff, 100);
};
self.update = function () {
self.x += self.vx;
self.y += self.vy;
self.rotation += self.rotationSpeed;
};
return self;
});
// Black Hole Hazard Class
var BlackHole = Container.expand(function () {
var self = Container.call(this);
var bhGraphics = self.attachAsset('star', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 8,
scaleY: 8,
tint: 0x222222
});
self.radius = 200;
self.pullStrength = 0.7 + Math.random() * 0.5;
self.damageRadius = 120;
self.update = function () {
// Animate black hole
bhGraphics.rotation += 0.03;
// Pull ship if in range
var dx = ship.x - self.x;
var dy = ship.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < self.radius) {
var pull = (self.radius - dist) / self.radius * self.pullStrength;
ship.x -= dx / dist * pull;
ship.y -= dy / dist * pull;
// Camera follows ship, so move all objects accordingly
for (var i = 0; i < stars.length; i++) {
stars[i].x -= dx / dist * pull;
stars[i].y -= dy / dist * pull;
}
for (var i = 0; i < npcs.length; i++) {
npcs[i].x -= dx / dist * pull;
npcs[i].y -= dy / dist * pull;
}
for (var i = 0; i < pirates.length; i++) {
pirates[i].x -= dx / dist * pull;
pirates[i].y -= dy / dist * pull;
}
for (var i = 0; i < coins.length; i++) {
coins[i].x -= dx / dist * pull;
coins[i].y -= dy / dist * pull;
}
for (var i = 0; i < resources.length; i++) {
resources[i].x -= dx / dist * pull;
resources[i].y -= dy / dist * pull;
}
for (var i = 0; i < bullets.length; i++) {
bullets[i].x -= dx / dist * pull;
bullets[i].y -= dy / dist * pull;
}
for (var i = 0; i < enemyBullets.length; i++) {
enemyBullets[i].x -= dx / dist * pull;
enemyBullets[i].y -= dy / dist * pull;
}
for (var i = 0; i < asteroids.length; i++) {
asteroids[i].x -= dx / dist * pull;
asteroids[i].y -= dy / dist * pull;
}
for (var i = 0; i < upgradeStations.length; i++) {
upgradeStations[i].x -= dx / dist * pull;
upgradeStations[i].y -= dy / dist * pull;
}
// boostParticles removed (no boost system)
for (var i = 0; i < explosions.length; i++) {
explosions[i].x -= dx / dist * pull;
explosions[i].y -= dy / dist * pull;
}
}
// Damage ship if too close
if (dist < self.damageRadius) {
if (!self.lastDamaged || LK.ticks - self.lastDamaged > 30) {
ship.takeDamage(10);
self.lastDamaged = LK.ticks;
LK.effects.flashObject(ship, 0x000000, 200);
}
}
};
return self;
});
var Bullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 15;
self.damage = 10;
self.directionX = 0;
self.directionY = -1;
self.update = function () {
self.x += self.directionX * self.speed;
self.y += self.directionY * self.speed;
};
return self;
});
var Coin = Container.expand(function () {
var self = Container.call(this);
var coinGraphics = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
self.value = Math.floor(Math.random() * 10) + 5;
self.update = function () {
self.rotation += 0.05;
};
return self;
});
var EnemyBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('enemyBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.damage = 5;
self.directionX = 0;
self.directionY = 0;
self.update = function () {
self.x += self.directionX * self.speed;
self.y += self.directionY * self.speed;
};
return self;
});
// HealthBar class for displaying health above entities
var HealthBar = Container.expand(function () {
var self = Container.call(this);
// width, height, color, maxValue, getValueFn
self._width = 60;
self._height = 10;
self._color = 0x00ff00;
self._maxValue = 100;
self._getValueFn = null;
self._getMaxFn = null;
self._bg = self.attachAsset('resource', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: self._width / 40,
scaleY: self._height / 40,
tint: 0x222222
});
self._bar = self.attachAsset('resource', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: (self._width - 4) / 40,
scaleY: (self._height - 4) / 40,
tint: self._color
});
self._bar.x = 0;
self._bar.y = 0;
self.set = function (opts) {
self._maxValue = opts.maxValue || 100;
self._getValueFn = opts.getValueFn;
self._getMaxFn = opts.getMaxFn;
self._color = opts.color || 0x00ff00;
self._bar.tint = self._color;
if (opts.width) {
self._width = opts.width;
self._bg.scaleX = self._width / 40;
self._bar.scaleX = (self._width - 4) / 40;
}
if (opts.height) {
self._height = opts.height;
self._bg.scaleY = self._height / 40;
self._bar.scaleY = (self._height - 4) / 40;
}
};
self.update = function () {
var value = self._getValueFn ? self._getValueFn() : self._maxValue;
var maxValue = self._getMaxFn ? self._getMaxFn() : self._maxValue;
var ratio = Math.max(0, Math.min(1, value / maxValue));
// Color: green > yellow > red
if (ratio > 0.6) {
self._bar.tint = 0x00ff00;
} else if (ratio > 0.3) {
self._bar.tint = 0xffff00;
} else {
self._bar.tint = 0xff0000;
}
self._bar.scaleX = (self._width - 4) * ratio / 40;
};
return self;
});
var NPC = Container.expand(function () {
var self = Container.call(this);
var npcGraphics = self.attachAsset('npc', {
anchorX: 0.5,
anchorY: 0.5
});
self.isAI = true; // AI-driven
self.baseY = 0;
self.moveSpeed = 1 + Math.random() * 2;
self.moveAngle = Math.random() * Math.PI * 2;
self.wanderTimer = 0;
self.lastAIAction = 0;
self.targetX = null;
self.targetY = null;
self.rpgName = "NPC-" + Math.floor(Math.random() * 10000);
// --- NPC Level System ---
// Level range: wave 1 => 1-3, wave 2 => 3-5, wave 3 => 5-7, etc.
var minLevel = 1 + (typeof waveNumber !== "undefined" ? waveNumber : 0) * 2;
var maxLevel = minLevel + 2;
self.level = minLevel + Math.floor(Math.random() * (maxLevel - minLevel + 1));
self.health = 100 + (self.level - 1) * 10;
// --- Level Text ---
self._levelText = new Text2("Lv." + self.level, {
size: 22,
fill: 0xcccccc,
align: "center"
});
self._levelText.anchor.set(0.5, 0);
self._levelText.x = 0;
self._levelText.y = 40; // Under the NPC sprite
self.addChild(self._levelText);
// Only floating AI logic, no quests/events/trade
// Add dummy interact method to prevent TypeError
self.interact = function () {
// No interaction for basic NPCs, return empty string
return "";
};
self.update = function () {
// Update level text position in case of movement
if (self._levelText) {
self._levelText.x = 0;
self._levelText.y = npcGraphics.height / 2 + 4;
self._levelText.setText("Lv." + self.level);
}
// Pause logic: If pauseUntil is set and not expired, skip movement
if (self.pauseUntil && LK.ticks < self.pauseUntil) {
// Still paused, only float animation
self.y += Math.sin(LK.ticks * 0.05) * 0.5;
return;
}
// AI: Sometimes move toward a random point, sometimes wander
self.wanderTimer++;
if (self.wanderTimer > 120 + Math.random() * 120) {
if (Math.random() < 0.5) {
// Pick a random point to move toward (simulate AI goal seeking)
self.targetX = self.x + (Math.random() - 0.5) * 800;
self.targetY = self.y + (Math.random() - 0.5) * 800;
} else {
self.targetX = null;
self.targetY = null;
}
self.moveAngle = Math.random() * Math.PI * 2;
self.wanderTimer = 0;
}
// Move toward target if set, else wander
if (self.targetX !== null && self.targetY !== null) {
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 10) {
self.x += dx / dist * self.moveSpeed;
self.y += dy / dist * self.moveSpeed;
self.moveAngle = Math.atan2(dy, dx);
} else {
self.targetX = null;
self.targetY = null;
}
} else {
self.x += Math.cos(self.moveAngle) * self.moveSpeed;
self.y += Math.sin(self.moveAngle) * self.moveSpeed;
}
// Float animation on top of movement
self.y += Math.sin(LK.ticks * 0.05) * 0.5;
};
return self;
});
var Pirate = Container.expand(function () {
var self = Container.call(this);
var pirateGraphics = self.attachAsset('pirate', {
anchorX: 0.5,
anchorY: 0.5
});
// --- Pirate Level & Scaling ---
self.level = typeof waveNumber !== "undefined" ? 1 + waveNumber : 1;
self.health = 30 + (self.level - 1) * 10;
self.speed = 2 + Math.floor((self.level - 1) / 10) * 0.2; // Slight speed up every 10 waves
self.fireRate = 60 - Math.min((self.level - 1) * 2, 30); // Faster fire at higher levels
self.lastFire = 0;
self.loot = Math.floor(Math.random() * 30) + 10 + (self.level - 1) * 2;
self.moveAngle = Math.random() * Math.PI * 2;
self.patrolTimer = 0;
self.aggroRange = 600;
// Korsan saldırı ve savunma gücü seviyeye göre orantılı artar
self.damage = 5 + Math.floor((self.level - 1) * 1.5); // Saldırı gücü daha hızlı artar
self.defense = 2 + Math.floor((self.level - 1) * 1.2); // Savunma gücü de seviyeye göre artar
// --- Level Text ---
self._levelText = new Text2("Lv." + self.level, {
size: 22,
fill: 0xcccccc,
align: "center"
});
self._levelText.anchor.set(0.5, 0);
self._levelText.x = 0;
self._levelText.y = 40; // Under the pirate sprite
self.addChild(self._levelText);
// Level text only, defense text removed
self.takeDamage = function (amount) {
self.health -= amount;
LK.effects.flashObject(self, 0xffffff, 100);
};
self.update = function () {
// Update level text position in case of movement
if (self._levelText) {
self._levelText.x = 0;
self._levelText.y = pirateGraphics.height / 2 + 4;
self._levelText.setText("Lv." + self.level);
}
// Defense text removed
// Movement AI
self.patrolTimer++;
if (self.patrolTimer > 180) {
self.moveAngle = Math.random() * Math.PI * 2;
self.patrolTimer = 0;
}
// Patrol movement
if (self._squadTargetNPC && self._squadTargetNPC.questType === 'defend' && self._squadTargetNPC.questActive) {
// Korsan, NPC'yi hedefle
var target = self._squadTargetNPC;
// Eğer defend quest'te yardım kabul edildiyse, oyuncuya da saldırabilir
if (target._defendHelpAccepted === true && Math.random() < 0.5) {
// %50 ihtimalle oyuncuya saldır
target = Math.random() < 0.5 ? self._squadTargetNPC : ship;
}
var dx = target.x - self.x;
var dy = target.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 10) {
self.x += dx / dist * self.speed;
self.y += dy / dist * self.speed;
self.moveAngle = Math.atan2(dy, dx);
}
// Ateş et
if (LK.ticks - self.lastFire > self.fireRate) {
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y;
var angle = Math.atan2(target.y - self.y, target.x - self.x);
bullet.directionX = Math.cos(angle);
bullet.directionY = Math.sin(angle);
bullet.rotation = angle + Math.PI / 2;
enemyBullets.push(bullet);
if (game && game.addChild) game.addChild(bullet);
self.lastFire = LK.ticks;
}
} else {
self.x += Math.cos(self.moveAngle) * self.speed * 0.5;
self.y += Math.sin(self.moveAngle) * self.speed * 0.5;
}
};
return self;
});
// Pirate Base Class
var PirateBase = Container.expand(function () {
var self = Container.call(this);
var baseGraphics = self.attachAsset('pirate', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0x990000,
scaleX: 3,
scaleY: 3
});
self.health = 300;
self.maxHealth = 300;
self.attackPower = 10;
self.defensePower = 10;
self.spawnRadius = 350;
self.pirates = [];
self.lastPirateSpawn = 0;
self.maxPirates = 10;
self._destroyed = false;
// Health bar
self._healthBar = new HealthBar();
self._healthBar.set({
maxValue: function maxValue() {
return self.maxHealth;
},
getValueFn: function getValueFn() {
return self.health;
},
getMaxFn: function getMaxFn() {
return self.maxHealth;
},
width: 120,
height: 16,
color: 0xff0000
});
self._healthBar.y = -120;
self.addChild(self._healthBar);
self.takeDamage = function (amount) {
self.health -= amount;
LK.effects.flashObject(self, 0xff0000, 120);
if (self.health <= 0 && !self._destroyed) {
self.health = 0;
self._destroyed = true;
// Remove all pirates around base
for (var i = 0; i < self.pirates.length; i++) {
if (self.pirates[i] && !self.pirates[i]._destroyed) {
self.pirates[i].destroy();
}
}
// Explosion effect
createExplosion(self.x, self.y);
// Floating label
var label = new Text2("Korsan Üssü Yok Edildi!", {
size: 48,
fill: 0xffcc00,
align: "center"
});
label.anchor.set(0.5, 0.5);
label.x = self.x;
label.y = self.y - 180;
if (game && game.addChild) game.addChild(label);
self._destroyed = true;
self.destroy();
}
};
self.update = function () {
// Health bar update
if (self._healthBar && self._healthBar.update) self._healthBar.update();
// Remove dead pirates from list
for (var i = self.pirates.length - 1; i >= 0; i--) {
if (!self.pirates[i] || self.pirates[i]._destroyed) {
self.pirates.splice(i, 1);
}
}
// Spawn pirates if less than max
if (!self._destroyed && self.pirates.length < self.maxPirates && LK.ticks - self.lastPirateSpawn > 90) {
var pirate = new Pirate();
var angle = Math.random() * Math.PI * 2;
pirate.x = self.x + Math.cos(angle) * (self.spawnRadius + Math.random() * 60);
pirate.y = self.y + Math.sin(angle) * (self.spawnRadius + Math.random() * 60);
pirate.health = 30 + self.attackPower * 2;
pirate.damage = 5 + self.attackPower;
pirate.rpgName = "BaseKorsan-" + Math.floor(Math.random() * 10000);
pirate._baseRef = self;
// Add health bar to pirate
pirate._healthBar = new HealthBar();
pirate._healthBar.set({
maxValue: function maxValue() {
return pirate.health > 0 ? pirate.health : 0;
},
getValueFn: function getValueFn() {
return pirate.health > 0 ? pirate.health : 0;
},
getMaxFn: function getMaxFn() {
return 30 + self.attackPower * 2;
},
width: 60,
height: 10
});
pirate._healthBar.y = -60;
pirate.addChild(pirate._healthBar);
pirates.push(pirate);
self.pirates.push(pirate);
if (game && game.addChild) game.addChild(pirate);
self.lastPirateSpawn = LK.ticks;
}
// Base defense: shoot at player if close
var distToShip = Math.sqrt(Math.pow(ship.x - self.x, 2) + Math.pow(ship.y - self.y, 2));
if (!self._destroyed && distToShip < self.spawnRadius + 80 && LK.ticks % 30 === 0) {
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y;
var angle = Math.atan2(ship.y - self.y, ship.x - self.x);
bullet.directionX = Math.cos(angle);
bullet.directionY = Math.sin(angle);
bullet.rotation = angle + Math.PI / 2;
bullet.damage = 10 + self.attackPower;
enemyBullets.push(bullet);
if (game && game.addChild) game.addChild(bullet);
}
};
return self;
});
var Resource = Container.expand(function () {
var self = Container.call(this);
var resourceGraphics = self.attachAsset('resource', {
anchorX: 0.5,
anchorY: 0.5
});
// 10 farklı hammadde tipi
var resourceTypes = ['metal', 'energy', 'crystal', 'gas', 'ice', 'uranium', 'silicon', 'carbon', 'plasma', 'antimatter'];
// --- Değerli hammaddelerin daha az çıkmasını sağlamak için ağırlıklı seçim ---
// Market kaldırıldı, sabit fiyatlar kullanılıyor
var prices = [100, 80, 120, 90, 70, 200, 110, 60, 150, 300];
// Her hammaddenin ağırlığı: 1 / (fiyat^0.7) ile ters orantılı (daha değerli = daha az)
// 0.7 üssüyle daha yumuşak bir dağılım, istenirse 1.0 yapılabilir
var weights = [];
var totalWeight = 0;
for (var i = 0; i < prices.length; i++) {
var w = 1 / Math.pow(prices[i], 0.7);
weights.push(w);
totalWeight += w;
}
// Rastgele ağırlıklı seçim
var r = Math.random() * totalWeight;
var acc = 0,
idx = 0;
for (var i = 0; i < weights.length; i++) {
acc += weights[i];
if (r <= acc) {
idx = i;
break;
}
}
self.type = resourceTypes[idx];
// Miktar: Değerli hammaddelerde miktar da az olsun
// maxAmount = 1 + 4 * (ucuzluk ağırlığı)
var maxAmount = Math.max(1, Math.round(1 + 4 * (weights[idx] / totalWeight * prices.length)));
self.amount = Math.floor(Math.random() * maxAmount) + 1;
self.update = function () {
self.rotation += 0.03;
};
return self;
});
var Ship = Container.expand(function () {
var self = Container.call(this);
var shipGraphics = self.attachAsset('ship', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 100;
self.maxHealth = 100;
self.shield = 50;
self.maxShield = 50;
self.shieldRegenDelay = 0;
self.speed = 5;
self.fireRate = 10;
self.damage = 10;
self.lastFire = 0;
self.takeDamage = function (amount) {
// Shield absorbs damage first
if (self.shield > 0) {
var shieldDamage = Math.min(amount, self.shield);
self.shield -= shieldDamage;
amount -= shieldDamage;
LK.effects.flashObject(self, 0x0088ff, 100);
self.shieldRegenDelay = 180; // 3 seconds delay before shield regen
}
if (amount > 0) {
self.health -= amount;
LK.effects.flashObject(self, 0xff0000, 200);
}
if (self.health <= 0) {
self.health = 0;
// --- NO GAME OVER: Respawn with 50% coin/resource loss ---
// 1. Lose 50% coins
var lostCoins = Math.floor(playerCoins * 0.5);
playerCoins = Math.max(0, playerCoins - lostCoins);
// 2. Lose 50% of each resource
for (var i = 0; i < playerResources.length; i++) {
playerResources[i] = Math.floor(playerResources[i] * 0.5);
}
// 3. Show floating label for penalty
var penaltyLabel = new Text2("-" + lostCoins + " coin\nHammadde ve coin kaybı! Yeniden doğdun.", {
size: 48,
fill: 0xff4444,
align: "center"
});
penaltyLabel.anchor.set(0.5, 0.5);
penaltyLabel.x = self.x;
penaltyLabel.y = self.y - 120;
if (typeof game !== "undefined" && game.addChild) game.addChild(penaltyLabel);
LK.setTimeout(function () {
if (penaltyLabel.parent) penaltyLabel.parent.removeChild(penaltyLabel);
}, 1800);
// 4. Respawn ship at a random safe location (not too close to pirates)
var safe = false,
tries = 0,
newX,
newY;
while (!safe && tries < 20) {
var angle = Math.random() * Math.PI * 2;
var dist = 800 + Math.random() * 1200;
newX = self.x + Math.cos(angle) * dist;
newY = self.y + Math.sin(angle) * dist;
safe = true;
for (var i = 0; i < pirates.length; i++) {
var pdist = Math.sqrt(Math.pow(pirates[i].x - newX, 2) + Math.pow(pirates[i].y - newY, 2));
if (pdist < 400) {
safe = false;
break;
}
}
tries++;
}
self.x = newX;
self.y = newY;
// 5. Restore health and shield
self.health = self.maxHealth;
self.shield = self.maxShield;
self.shieldRegenDelay = 180;
// 6. Update UI and save progress
if (typeof updateUI === "function") updateUI();
if (typeof saveProgress === "function") saveProgress();
}
};
self.update = function () {
// Shield regeneration
if (self.shieldRegenDelay > 0) {
self.shieldRegenDelay--;
} else if (self.shield < self.maxShield) {
self.shield = Math.min(self.shield + 0.1, self.maxShield);
}
};
return self;
});
var Star = Container.expand(function () {
var self = Container.call(this);
var starGraphics = self.attachAsset('star', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = Math.random() * 2 + 0.5;
starGraphics.alpha = Math.random() * 0.8 + 0.2;
self.vx = (Math.random() - 0.5) * 0.5;
self.vy = (Math.random() - 0.5) * 0.5;
self.update = function () {
// Slow floating movement
self.x += self.vx;
self.y += self.vy;
};
return self;
});
// Suçlu (Criminal) Class - 10x stronger and 10x more rewarding than Pirate
var Suclu = Container.expand(function () {
var self = Container.call(this);
// Use 'alien' asset for visual distinction (could be replaced with a unique asset if available)
var sucluGraphics = self.attachAsset('alien', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0xff00ff,
// Magenta for visual difference
scaleX: 1.2,
scaleY: 1.2
});
// --- Suçlu Level & Scaling ---
self.level = typeof waveNumber !== "undefined" ? 1 + waveNumber : 1;
self.health = 300 + (self.level - 1) * 100; // 10x Pirate health
self.speed = 2.5 + Math.floor((self.level - 1) / 10) * 0.2;
self.fireRate = 40 - Math.min((self.level - 1) * 2, 20); // Faster fire
self.lastFire = 0;
self.loot = (Math.floor(Math.random() * 30) + 10 + (self.level - 1) * 2) * 10; // 10x Pirate loot
self.moveAngle = Math.random() * Math.PI * 2;
self.patrolTimer = 0;
self.aggroRange = 700;
self.damage = (5 + Math.floor((self.level - 1) * 1.5)) * 10; // 10x Pirate damage
self.defense = (2 + Math.floor((self.level - 1) * 1.2)) * 10; // 10x Pirate defense
// --- Level Text ---
self._levelText = new Text2("Lv." + self.level, {
size: 28,
fill: 0xff00ff,
align: "center"
});
self._levelText.anchor.set(0.5, 0);
self._levelText.x = 0;
self._levelText.y = 50;
self.addChild(self._levelText);
// Health bar
self._healthBar = new HealthBar();
self._healthBar.set({
maxValue: function maxValue() {
return self.health > 0 ? self.health : 0;
},
getValueFn: function getValueFn() {
return self.health > 0 ? self.health : 0;
},
getMaxFn: function getMaxFn() {
return 300 + (self.level - 1) * 100;
},
width: 80,
height: 14,
color: 0xff00ff
});
self._healthBar.y = -70;
self.addChild(self._healthBar);
self.takeDamage = function (amount) {
self.health -= amount;
LK.effects.flashObject(self, 0xffffff, 100);
};
self.update = function () {
// Update level text position
if (self._levelText) {
self._levelText.x = 0;
self._levelText.y = sucluGraphics.height / 2 + 8;
self._levelText.setText("Lv." + self.level);
}
if (self._healthBar && self._healthBar.update) self._healthBar.update();
// Movement AI (similar to Pirate, but more aggressive)
self.patrolTimer++;
if (self.patrolTimer > 120) {
self.moveAngle = Math.random() * Math.PI * 2;
self.patrolTimer = 0;
}
// Find nearest target (NPC or player)
var nearestTarget = null;
var minDist = Infinity;
for (var n = 0; n < npcs.length; n++) {
var npc = npcs[n];
var distToNPC = Math.sqrt(Math.pow(npc.x - self.x, 2) + Math.pow(npc.y - self.y, 2));
if (distToNPC < minDist) {
minDist = distToNPC;
nearestTarget = npc;
}
}
var distToPlayer = Math.sqrt(Math.pow(ship.x - self.x, 2) + Math.pow(ship.y - self.y, 2));
if (distToPlayer < minDist) {
minDist = distToPlayer;
nearestTarget = ship;
}
// If there is a target, move and attack
if (nearestTarget && minDist < self.aggroRange) {
var targetRadius = 50;
if (nearestTarget._healthBar && nearestTarget._healthBar._width) {
targetRadius = Math.max(targetRadius, nearestTarget._healthBar._width / 2);
}
var selfRadius = 45;
if (self._healthBar && self._healthBar._width) {
selfRadius = Math.max(selfRadius, self._healthBar._width / 2);
}
var minBuffer = (minDist + selfRadius + targetRadius) * 0.05;
var minAllowedDist = selfRadius + targetRadius + minBuffer;
var angle = Math.atan2(nearestTarget.y - self.y, nearestTarget.x - self.x);
if (minDist > minAllowedDist) {
var moveDist = Math.min(self.speed, minDist - minAllowedDist);
self.x += Math.cos(angle) * moveDist;
self.y += Math.sin(angle) * moveDist;
self.rotation = angle + Math.PI / 2;
} else {
self.rotation = angle + Math.PI / 2;
}
// Shoot at target
if (LK.ticks - self.lastFire > self.fireRate) {
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y;
bullet.directionX = Math.cos(angle);
bullet.directionY = Math.sin(angle);
bullet.rotation = angle + Math.PI / 2;
bullet.damage = self.damage;
bullet._sucluBullet = true;
enemyBullets.push(bullet);
if (game && game.addChild) game.addChild(bullet);
self.lastFire = LK.ticks;
}
} else {
// Wander randomly
self.x += Math.cos(self.moveAngle) * self.speed * 0.5;
self.y += Math.sin(self.moveAngle) * self.speed * 0.5;
}
};
return self;
});
// Trade Station Class
var TradeStation = Container.expand(function () {
var self = Container.call(this);
var tradeGraphics = self.attachAsset('npc', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0x00ff99,
scaleX: 2,
scaleY: 2
});
self.type = 'trade';
self.rotationSpeed = 0.01;
self.offerType = Math.random() < 0.5 ? 'buy' : 'sell'; // buy: station buys from player, sell: station sells to player
self.resourceType = Math.random() < 0.5 ? 'metal' : 'energy';
self.amount = Math.floor(Math.random() * 10) + 5;
self.price = Math.floor(Math.random() * 30) + 10;
self.specialOffer = Math.random() < 0.2; // 20% chance for special upgrade offer
self.specialUpgrade = null;
if (self.specialOffer) {
var upgrades = [{
name: 'maxHealth',
label: 'Max Health +30',
cost: 200
}, {
name: 'maxShield',
label: 'Max Shield +20',
cost: 180
}, {
name: 'damage',
label: 'Damage +5',
cost: 150
}, {
name: 'speed',
label: 'Speed +1',
cost: 120
}];
self.specialUpgrade = upgrades[Math.floor(Math.random() * upgrades.length)];
}
self.update = function () {
self.rotation += self.rotationSpeed;
// Pulse effect
var scale = 2 + Math.sin(LK.ticks * 0.05) * 0.1;
tradeGraphics.scaleX = scale;
tradeGraphics.scaleY = scale;
};
return self;
});
var UpgradeStation = Container.expand(function () {
var self = Container.call(this);
var stationGraphics = self.attachAsset('pirate', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0x00ffff,
scaleX: 1.5,
scaleY: 1.5
});
self.type = 'upgrade';
self.upgrades = [{
name: 'health',
cost: 100,
metalCost: 10
}, {
name: 'shield',
cost: 150,
metalCost: 15
}, {
name: 'damage',
cost: 200,
energyCost: 20
}, {
name: 'speed',
cost: 120,
energyCost: 10
}];
self.currentUpgrade = 0;
self.rotationSpeed = 0.01;
self.update = function () {
self.rotation += self.rotationSpeed;
// Pulse effect
var scale = 1.5 + Math.sin(LK.ticks * 0.05) * 0.1;
stationGraphics.scaleX = scale;
stationGraphics.scaleY = scale;
};
return self;
});
// Wormhole Teleporter Class
var Wormhole = Container.expand(function () {
var self = Container.call(this);
var whGraphics = self.attachAsset('star', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 5,
scaleY: 5,
tint: 0x00ffff
});
self.radius = 120;
self.cooldown = 0;
self.update = function () {
whGraphics.rotation += 0.07;
// Teleport ship if close and not on cooldown
var dx = ship.x - self.x;
var dy = ship.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < self.radius && self.cooldown <= 0) {
// Teleport ship to a random far location
var tx = ship.x + (Math.random() - 0.5) * 4000;
var ty = ship.y + (Math.random() - 0.5) * 4000;
var dx2 = tx - ship.x;
var dy2 = ty - ship.y;
ship.x = tx;
ship.y = ty;
// Move all objects to keep camera effect
for (var i = 0; i < stars.length; i++) {
stars[i].x -= dx2;
stars[i].y -= dy2;
}
for (var i = 0; i < npcs.length; i++) {
npcs[i].x -= dx2;
npcs[i].y -= dy2;
}
for (var i = 0; i < pirates.length; i++) {
pirates[i].x -= dx2;
pirates[i].y -= dy2;
}
for (var i = 0; i < coins.length; i++) {
coins[i].x -= dx2;
coins[i].y -= dy2;
}
for (var i = 0; i < resources.length; i++) {
resources[i].x -= dx2;
resources[i].y -= dy2;
}
for (var i = 0; i < bullets.length; i++) {
bullets[i].x -= dx2;
bullets[i].y -= dy2;
}
for (var i = 0; i < enemyBullets.length; i++) {
enemyBullets[i].x -= dx2;
enemyBullets[i].y -= dy2;
}
for (var i = 0; i < asteroids.length; i++) {
asteroids[i].x -= dx2;
asteroids[i].y -= dy2;
}
for (var i = 0; i < upgradeStations.length; i++) {
upgradeStations[i].x -= dx2;
upgradeStations[i].y -= dy2;
}
// boostParticles removed (no boost system)
for (var i = 0; i < explosions.length; i++) {
explosions[i].x -= dx2;
explosions[i].y -= dy2;
}
for (var i = 0; i < blackHoles.length; i++) {
blackHoles[i].x -= dx2;
blackHoles[i].y -= dy2;
}
for (var i = 0; i < wormholes.length; i++) {
if (wormholes[i] !== self) {
wormholes[i].x -= dx2;
wormholes[i].y -= dy2;
}
}
self.cooldown = 180;
LK.effects.flashScreen(0x00ffff, 500);
}
if (self.cooldown > 0) self.cooldown--;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000033
});
/****
* Game Code
****/
// (No other LK.showGameOver() in Game Code section)
var ship;
var joystickBase;
var joystickHandle;
var isDragging = false;
var bullets = [];
var enemyBullets = [];
var npcs = [];
var pirates = [];
var suclus = [];
var coins = [];
var resources = [];
var stars = [];
var asteroids = [];
var upgradeStations = [];
var explosions = [];
var blackHoles = [];
var wormholes = [];
var tradeStations = [];
var pirateBases = [];
var tradeText = null; // No trade text needed
// Helper: spawn a pirate base at a random edge, with pirates around it
function spawnPirateBase() {
var base = new PirateBase();
// Spawn from edges of visible area
var edge = Math.floor(Math.random() * 4);
switch (edge) {
case 0:
// Top
base.x = ship.x + (Math.random() - 0.5) * 2000;
base.y = ship.y - 1600;
break;
case 1:
// Right
base.x = ship.x + 1600;
base.y = ship.y + (Math.random() - 0.5) * 2000;
break;
case 2:
// Bottom
base.x = ship.x + (Math.random() - 0.5) * 2000;
base.y = ship.y + 1600;
break;
case 3:
// Left
base.x = ship.x - 1600;
base.y = ship.y + (Math.random() - 0.5) * 2000;
break;
// --- MINI MAP OVERLAY DRAW/UPDATE ---
if (window._miniMapVisible) {
// Helper to convert world to mini map
var toMiniMap = function toMiniMap(wx, wy) {
return {
x: mapCenterX + (wx - ship.x) * mapScale,
y: mapCenterY + (wy - ship.y) * mapScale
};
}; // Draw ship
// Create container if not exists
if (!window._miniMapContainer) {
var miniMapContainer = new Container();
// Position: below the ship, centered horizontally
// Ship is at (ship.x, ship.y) in world, but we want minimap in screen coordinates
// Center horizontally, and place just below the ship (ship.y + ship height/2 + margin)
var mapSize = 480;
var marginBelowShip = 80;
var screenW = 2048,
screenH = 2732;
var miniMapX = (screenW - mapSize) / 2;
var miniMapY = Math.min(screenH - mapSize - 40, Math.max(0, ship.y + 100 + marginBelowShip - mapSize / 2));
// Clamp to screen
miniMapY = Math.max(200, Math.min(screenH - mapSize - 40, miniMapY));
miniMapContainer.x = miniMapX;
miniMapContainer.y = miniMapY;
window._miniMapContainer = miniMapContainer;
game.addChild(miniMapContainer);
}
var miniMapContainer = window._miniMapContainer;
// Remove previous elements
for (var i = 0; i < window._miniMapElements.length; i++) {
if (window._miniMapElements[i] && window._miniMapElements[i].parent) {
window._miniMapElements[i].parent.removeChild(window._miniMapElements[i]);
}
}
window._miniMapElements = [];
// Draw background
var bg = LK.getAsset('resource', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
scaleX: 12,
scaleY: 12,
tint: 0x111133,
alpha: 0.92
});
miniMapContainer.addChild(bg);
window._miniMapElements.push(bg);
// Draw border
var border = LK.getAsset('resource', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
scaleX: 12,
scaleY: 12,
tint: 0x00ccff,
alpha: 0.25
});
miniMapContainer.addChild(border);
window._miniMapElements.push(border);
// Mini map covers 6000x6000 px area centered on ship
var mapSize = 480;
var worldSize = 6000;
var halfWorld = worldSize / 2;
var mapScale = mapSize / worldSize;
var mapCenterX = mapSize / 2;
var mapCenterY = mapSize / 2;
var shipPos = toMiniMap(ship.x, ship.y);
var shipDot = LK.getAsset('ship', {
anchorX: 0.5,
anchorY: 0.5,
x: shipPos.x,
y: shipPos.y,
scaleX: 0.3,
scaleY: 0.3,
tint: 0x00ff00,
alpha: 1
});
miniMapContainer.addChild(shipDot);
window._miniMapElements.push(shipDot);
// Draw pirates
for (var i = 0; i < pirates.length; i++) {
var p = pirates[i];
if (p._destroyed) continue;
var pos = toMiniMap(p.x, p.y);
var pirateDot = LK.getAsset('pirate', {
anchorX: 0.5,
anchorY: 0.5,
x: pos.x,
y: pos.y,
scaleX: 0.18,
scaleY: 0.18,
tint: 0xff4444,
alpha: 0.85
});
miniMapContainer.addChild(pirateDot);
window._miniMapElements.push(pirateDot);
}
// Draw NPCs
for (var i = 0; i < npcs.length; i++) {
var n = npcs[i];
var pos = toMiniMap(n.x, n.y);
var npcDot = LK.getAsset('npc', {
anchorX: 0.5,
anchorY: 0.5,
x: pos.x,
y: pos.y,
scaleX: 0.18,
scaleY: 0.18,
tint: 0x00ccff,
alpha: 0.85
});
miniMapContainer.addChild(npcDot);
window._miniMapElements.push(npcDot);
// If NPC has active quest target, draw target marker
if (n.questActive && n.questTarget) {
var tx, ty;
if (n.questType === 'hunt' && n.questTarget.x !== undefined && n.questTarget.y !== undefined && !n.questTarget._destroyed) {
tx = n.questTarget.x;
ty = n.questTarget.y;
} else if (n.questTarget.x !== undefined && n.questTarget.y !== undefined) {
tx = n.questTarget.x;
ty = n.questTarget.y;
}
if (typeof tx === "number" && typeof ty === "number") {
var tpos = toMiniMap(tx, ty);
var color = 0xffff00;
if (n.questType === 'explore') color = 0x00ffcc;
if (n.questType === 'delivery') color = 0xffcc00;
if (n.questType === 'escort') color = 0x00ff99;
if (n.questType === 'hunt') color = 0xff4444;
var targetDot = LK.getAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5,
x: tpos.x,
y: tpos.y,
scaleX: 0.22,
scaleY: 0.22,
tint: color,
alpha: 0.95
});
miniMapContainer.addChild(targetDot);
window._miniMapElements.push(targetDot);
// Add label
var label = new Text2(n.questType.charAt(0).toUpperCase() + n.questType.slice(1), {
size: 18,
fill: color,
align: "center"
});
label.anchor.set(0.5, 0);
label.x = tpos.x;
label.y = tpos.y + 12;
miniMapContainer.addChild(label);
window._miniMapElements.push(label);
}
}
}
// Draw derelict ship
if (window.derelictShip && window.derelictShip.x !== undefined && window.derelictShip.y !== undefined) {
var d = window.derelictShip;
var dpos = toMiniMap(d.x, d.y);
var derelictDot = LK.getAsset('ship', {
anchorX: 0.5,
anchorY: 0.5,
x: dpos.x,
y: dpos.y,
scaleX: 0.22,
scaleY: 0.22,
tint: 0xcccccc,
alpha: 0.8
});
miniMapContainer.addChild(derelictDot);
window._miniMapElements.push(derelictDot);
var label = new Text2("Gemi", {
size: 16,
fill: 0xcccccc,
align: "center"
});
label.anchor.set(0.5, 0);
label.x = dpos.x;
label.y = dpos.y + 10;
miniMapContainer.addChild(label);
window._miniMapElements.push(label);
}
// Draw distress event
if (window.distressEvent && window.distressEvent.x !== undefined && window.distressEvent.y !== undefined) {
var e = window.distressEvent;
var epos = toMiniMap(e.x, e.y);
var distressDot = LK.getAsset('star', {
anchorX: 0.5,
anchorY: 0.5,
x: epos.x,
y: epos.y,
scaleX: 0.22,
scaleY: 0.22,
tint: 0xff00ff,
alpha: 0.8
});
miniMapContainer.addChild(distressDot);
window._miniMapElements.push(distressDot);
var label = new Text2("İmdat", {
size: 16,
fill: 0xff00ff,
align: "center"
});
label.anchor.set(0.5, 0);
label.x = epos.x;
label.y = epos.y + 10;
miniMapContainer.addChild(label);
window._miniMapElements.push(label);
}
// Draw trade stations
for (var i = 0; i < tradeStations.length; i++) {
var ts = tradeStations[i];
var tpos = toMiniMap(ts.x, ts.y);
var tradeDot = LK.getAsset('npc', {
anchorX: 0.5,
anchorY: 0.5,
x: tpos.x,
y: tpos.y,
scaleX: 0.16,
scaleY: 0.16,
tint: 0x00ffcc,
alpha: 0.7
});
miniMapContainer.addChild(tradeDot);
window._miniMapElements.push(tradeDot);
}
// Draw upgrade stations
for (var i = 0; i < upgradeStations.length; i++) {
var us = upgradeStations[i];
var upos = toMiniMap(us.x, us.y);
var upgDot = LK.getAsset('pirate', {
anchorX: 0.5,
anchorY: 0.5,
x: upos.x,
y: upos.y,
scaleX: 0.16,
scaleY: 0.16,
tint: 0x00ffff,
alpha: 0.7
});
miniMapContainer.addChild(upgDot);
window._miniMapElements.push(upgDot);
}
// Draw black holes
for (var i = 0; i < blackHoles.length; i++) {
var bh = blackHoles[i];
var bhpos = toMiniMap(bh.x, bh.y);
var bhDot = LK.getAsset('star', {
anchorX: 0.5,
anchorY: 0.5,
x: bhpos.x,
y: bhpos.y,
scaleX: 0.18,
scaleY: 0.18,
tint: 0x222222,
alpha: 0.7
});
miniMapContainer.addChild(bhDot);
window._miniMapElements.push(bhDot);
}
// Draw wormholes
for (var i = 0; i < wormholes.length; i++) {
var wh = wormholes[i];
var whpos = toMiniMap(wh.x, wh.y);
var whDot = LK.getAsset('star', {
anchorX: 0.5,
anchorY: 0.5,
x: whpos.x,
y: whpos.y,
scaleX: 0.18,
scaleY: 0.18,
tint: 0x00ffff,
alpha: 0.7
});
miniMapContainer.addChild(whDot);
window._miniMapElements.push(whDot);
}
// Draw pirate bases
for (var i = 0; i < pirateBases.length; i++) {
var pb = pirateBases[i];
var pbpos = toMiniMap(pb.x, pb.y);
var pbDot = LK.getAsset('pirate', {
anchorX: 0.5,
anchorY: 0.5,
x: pbpos.x,
y: pbpos.y,
scaleX: 0.22,
scaleY: 0.22,
tint: 0xff00ff,
alpha: 0.8
});
miniMapContainer.addChild(pbDot);
window._miniMapElements.push(pbDot);
var label = new Text2("Üs", {
size: 16,
fill: 0xff00ff,
align: "center"
});
label.anchor.set(0.5, 0);
label.x = pbpos.x;
label.y = pbpos.y + 10;
miniMapContainer.addChild(label);
window._miniMapElements.push(label);
}
// Draw asteroids (only those close to ship)
for (var i = 0; i < asteroids.length; i++) {
var a = asteroids[i];
var dist = Math.sqrt(Math.pow(a.x - ship.x, 2) + Math.pow(a.y - ship.y, 2));
if (dist > 3000) continue;
var apos = toMiniMap(a.x, a.y);
var aDot = LK.getAsset('resource', {
anchorX: 0.5,
anchorY: 0.5,
x: apos.x,
y: apos.y,
scaleX: 0.12,
scaleY: 0.12,
tint: 0x8B4513,
alpha: 0.6
});
miniMapContainer.addChild(aDot);
window._miniMapElements.push(aDot);
}
// Draw label
var title = new Text2("Mini Map", {
size: 32,
fill: 0xffffff,
align: "center"
});
title.anchor.set(0.5, 0);
title.x = mapSize / 2;
title.y = 10;
miniMapContainer.addChild(title);
window._miniMapElements.push(title);
// Draw close hint
var hint = new Text2("Kapatmak için tekrar dokun", {
size: 18,
fill: 0xcccccc,
align: "center"
});
hint.anchor.set(0.5, 1);
hint.x = mapSize / 2;
hint.y = mapSize - 10;
miniMapContainer.addChild(hint);
window._miniMapElements.push(hint);
} else if (window._miniMapContainer && window._miniMapContainer.parent) {
window._miniMapContainer.parent.removeChild(window._miniMapContainer);
window._miniMapElements = [];
window._miniMapContainer = null;
}
}
;
pirateBases.push(base);
game.addChild(base);
// Spawn initial pirates around base
for (var i = 0; i < 10; i++) {
var pirate = new Pirate();
var angle = Math.PI * 2 * (i / 10);
pirate.x = base.x + Math.cos(angle) * (base.spawnRadius + Math.random() * 60);
pirate.y = base.y + Math.sin(angle) * (base.spawnRadius + Math.random() * 60);
// Level range: wave 1 => 1-3, wave 2 => 3-5, wave 3 => 5-7, etc.
var minLevel = 1 + waveNumber * 2;
var maxLevel = minLevel + 2;
pirate.level = minLevel + Math.floor(Math.random() * (maxLevel - minLevel + 1));
pirate.health = 30 + (pirate.level - 1) * 10 + base.attackPower * 2;
pirate.damage = 5 + Math.floor((pirate.level - 1) * 1.5) + base.attackPower;
pirate.defense = 2 + Math.floor((pirate.level - 1) * 1.2) + base.defensePower;
pirate.rpgName = "BaseKorsan-" + Math.floor(Math.random() * 10000);
pirate._baseRef = base;
// Add health bar to pirate
pirate._healthBar = new HealthBar();
pirate._healthBar.set({
maxValue: function maxValue() {
return pirate.health > 0 ? pirate.health : 0;
},
getValueFn: function getValueFn() {
return pirate.health > 0 ? pirate.health : 0;
},
getMaxFn: function getMaxFn() {
return 30 + base.attackPower * 2;
},
width: 60,
height: 10
});
pirate._healthBar.y = -60;
pirate.addChild(pirate._healthBar);
pirates.push(pirate);
base.pirates.push(pirate);
game.addChild(pirate);
}
}
// tradeText UI removed (no tradeText in this version)
var camera = {
x: 0,
y: 0
};
// --- Helper for multi-pirate attack quest ---
function spawnPirateSquad(centerX, centerY, count, targetNPC) {
var squad = [];
for (var i = 0; i < count; i++) {
var pirate = new Pirate();
var angle = Math.PI * 2 * (i / count);
pirate.x = centerX + Math.cos(angle) * 200 + (Math.random() - 0.5) * 60;
pirate.y = centerY + Math.sin(angle) * 200 + (Math.random() - 0.5) * 60;
// Level range: wave 1 => 1-3, wave 2 => 3-5, wave 3 => 5-7, etc.
var minLevel = 1 + waveNumber * 2;
var maxLevel = minLevel + 2;
pirate.level = minLevel + Math.floor(Math.random() * (maxLevel - minLevel + 1));
pirate.health = 30 + (pirate.level - 1) * 10;
pirate.damage = 5 + Math.floor((pirate.level - 1) * 1.5);
pirate.defense = 2 + Math.floor((pirate.level - 1) * 1.2);
pirate.rpgName = "Korsan-" + Math.floor(Math.random() * 10000);
pirate._squadTargetNPC = targetNPC;
pirates.push(pirate);
game.addChild(pirate);
squad.push(pirate);
}
return squad;
}
// Trade station tap detection (RPG/ticaret)
for (var i = 0; i < tradeStations.length; i++) {
var ts = tradeStations[i];
var dist = Math.sqrt(Math.pow(ts.x - ship.x, 2) + Math.pow(ts.y - ship.y, 2));
if (dist < 180) {
game._lastTradeStationTap = LK.ticks;
break;
}
}
var waveNumber = 0;
var enemiesKilled = 0;
var totalDistance = 0;
// Player stats
var playerCoins = storage.coins || 0;
// 10 hammadde için oyuncu envanteri
var playerResources = [storage.metal || 0,
// metal
storage.energy || 0,
// energy
storage.crystal || 0,
// crystal
storage.gas || 0,
// gas
storage.ice || 0,
// ice
storage.uranium || 0,
// uranium
storage.silicon || 0,
// silicon
storage.carbon || 0,
// carbon
storage.plasma || 0,
// plasma
storage.antimatter || 0 // antimatter
];
// Aliases for compatibility with old code
var playerMetal = playerResources[0];
var playerEnergy = playerResources[1];
var questsCompleted = storage.questsCompleted || 0;
// --- Player Level/EXP ---
var playerLevel = typeof storage.playerLevel !== "undefined" ? storage.playerLevel : 1;
var playerEXP = typeof storage.playerEXP !== "undefined" ? storage.playerEXP : 0;
function expToNext(level) {
// Simple EXP curve: next = 10 + 5*(level-1)
return 10 + 5 * (level - 1);
}
// UI Elements
// Calculate the unified font size (30% smaller than expText, then %10 büyüt)
var unifiedFontSize = Math.round(38 * 0.7 * 1.1);
var coinText = new Text2('Coins: ' + playerCoins, {
size: unifiedFontSize,
fill: 0xFFFF00
});
coinText.anchor.set(0, 0);
coinText.x = 120;
coinText.y = 20;
LK.gui.topLeft.addChild(coinText);
// --- NPC ile savaş butonu ---
var npcFightBtnFont = Math.round(unifiedFontSize * 1.1);
window.npcFightBtn = new Text2("NPC ile Savaş", {
size: npcFightBtnFont,
fill: 0xff4444,
align: "center"
});
window.npcFightBtn.anchor.set(0.5, 0.5);
// Place at bottom center, above the bottom edge
window.npcFightBtn.x = 2048 / 2;
window.npcFightBtn.y = 2732 - 300; // moved 2 lines (about 120px) higher
LK.gui.bottom.addChild(window.npcFightBtn);
window.npcFightMode = false;
// --- UZAY İSTASYONU TESLİMAT BUTTON (above Reset, 2 rows up) ---
if (!window.stationDeliveryBtn) {
var deliveryBtnFont = Math.round(unifiedFontSize * 1.1);
window.stationDeliveryBtn = new Text2("", {
size: deliveryBtnFont,
fill: 0x00ffcc,
align: "center"
});
window.stationDeliveryBtn.anchor.set(1, 1);
// Place 2 rows above Reset (row = 80px)
window.stationDeliveryBtn.x = -40;
window.stationDeliveryBtn.y = -40 - 2 * 90;
// Add image above the button, 10% higher (yukarıya %10)
if (!window.stationDeliveryBtnImage) {
// Use the special image for the transparent button area
var imgAsset = LK.getAsset('stationDeliveryBtnAreaImg', {
anchorX: 1,
anchorY: 1,
scaleX: 0.7,
scaleY: 0.7
});
// Place image at the same x, but y is 10% higher (10% of image height above the button)
// Keep the station image fixed (do not move it up)
imgAsset.x = window.stationDeliveryBtn.x;
imgAsset.y = window.stationDeliveryBtn.y - imgAsset.height * 1.1;
window.stationDeliveryBtnImage = imgAsset;
LK.gui.bottomRight.addChild(window.stationDeliveryBtnImage);
// Add a transparent button area exactly the size and position of the image for İstasyon Teslimat
var stationDeliveryBtnArea = new Text2("", {
size: 1,
fill: 0xffffff,
align: "center"
});
stationDeliveryBtnArea.anchor.set(1, 1);
// Place the button area exactly behind the image, matching its position and size
stationDeliveryBtnArea.x = imgAsset.x;
// Move the button area 1 row (imgAsset.height) above the image
stationDeliveryBtnArea.y = imgAsset.y - imgAsset.height;
stationDeliveryBtnArea.width = imgAsset.width;
stationDeliveryBtnArea.height = imgAsset.height;
stationDeliveryBtnArea.alpha = 0; // fully transparent, but still receives taps
window.stationDeliveryBtnArea = stationDeliveryBtnArea;
// Add the button area BEFORE the image so it is behind
LK.gui.bottomRight.addChild(stationDeliveryBtnArea);
LK.gui.bottomRight.addChild(window.stationDeliveryBtnImage);
}
LK.gui.bottomRight.addChild(window.stationDeliveryBtn);
// Add 'İstasyona Hammadde Gönder' text 2 rows below the button
if (!window.stationSendResourceText) {
var sendTextFont = Math.max(8, Math.round(unifiedFontSize * 1.0) - 2);
window.stationSendResourceText = new Text2("", {
size: sendTextFont,
fill: 0xffffff,
align: "center"
});
window.stationSendResourceText.anchor.set(1, 1);
// 2 rows below the stationDeliveryBtn (row = 90px)
window.stationSendResourceText.x = window.stationDeliveryBtn.x;
window.stationSendResourceText.y = window.stationDeliveryBtn.y + 1 * 90;
LK.gui.bottomRight.addChild(window.stationSendResourceText);
}
}
// --- RESET BUTTON (bottom right) ---
if (!game._resetBtn) {
game._resetBtn = new Text2("Reset", {
size: Math.round(unifiedFontSize * 1.1),
fill: 0xff4444,
align: "center"
});
game._resetBtn.anchor.set(1, 1);
// Place at bottom right, with margin from edge
game._resetBtn.x = -40;
game._resetBtn.y = -40;
LK.gui.bottomRight.addChild(game._resetBtn);
}
// --- UZAY İSTASYONU TESLİMAT PANEL SYSTEM ---
// State for delivery system
if (!window.stationDeliveryState) {
// 10 hammadde için rastgele 50-200 arası istek, bonus %2-5 arası
window.stationDeliveryState = {
requests: [],
delivered: [],
completed: false,
bonus: 0
};
for (var i = 0; i < 10; i++) {
var req = 50 + Math.floor(Math.random() * 151); // 50-200
window.stationDeliveryState.requests.push(req);
window.stationDeliveryState.delivered.push(0);
}
window.stationDeliveryState.bonus = 2 + Math.floor(Math.random() * 4); // 2-5
window.stationDeliveryState.completed = false;
window.stationDeliveryState.rewardClaimed = false;
}
// Helper to open/close panel
window.openStationDeliveryPanel = function () {
if (window.stationDeliveryPanel) return;
// Increase font size by 2 for all panel texts/buttons
var panelFontSize = unifiedFontSize + 2;
var panelBtnFontSize = panelFontSize;
var labelFontSize = panelFontSize;
var closeBtnFontSize = panelFontSize;
var claimBtnFontSize = panelFontSize;
var bonusFontSize = panelFontSize;
var infoFontSize = panelFontSize;
var titleFontSize = panelFontSize;
// Calculate new panel size to fit enlarged text/buttons
var rowH = 80 + 8; // add 8px for extra font size
var panelW = 900 + 120; // add width for larger text/buttons
var panelH = 1100 + 2 * rowH; // add height for larger text/buttons
var px = 1024,
py = 900;
// Panel BG
window.stationDeliveryPanelBG = LK.getAsset('resource', {
anchorX: 0.5,
anchorY: 0.5,
x: px,
y: py,
scaleX: panelW / 40,
scaleY: panelH / 40,
tint: 0x223355,
alpha: 0.97
});
// Title
window.stationDeliveryPanelTitle = new Text2("Uzay İstasyonu Teslimat", {
size: titleFontSize,
fill: 0x00ffcc,
align: "center"
});
window.stationDeliveryPanelTitle.anchor.set(0.5, 0);
window.stationDeliveryPanelTitle.x = px;
window.stationDeliveryPanelTitle.y = py - panelH / 2 + 40;
// Info text
window.stationDeliveryPanelInfoText = new Text2("İstasyonun özel hammadde isteklerini tamamla!\nTümünü teslim edince +" + window.stationDeliveryState.bonus + "% bonus fiyattan satılır.", {
size: infoFontSize,
fill: 0xffffff,
align: "center"
});
window.stationDeliveryPanelInfoText.anchor.set(0.5, 0);
window.stationDeliveryPanelInfoText.x = px;
window.stationDeliveryPanelInfoText.y = window.stationDeliveryPanelTitle.y + 60;
// Close button
window.stationDeliveryPanelCloseBtn = new Text2("Kapat", {
size: unifiedFontSize + 4,
// 2 font larger than Coins
fill: 0xff4444,
align: "center"
});
window.stationDeliveryPanelCloseBtn.anchor.set(0.5, 0.5);
// Move close button above the panel title, with extra margin
window.stationDeliveryPanelCloseBtn.x = px;
window.stationDeliveryPanelCloseBtn.y = window.stationDeliveryPanelTitle.y - 110; // further above title
// Resource request labels and delivery buttons
window.stationDeliveryLabels = [];
window.stationDeliveryDeliverBtns = [];
// Move all resource rows down by 3% of the panel height
var startY = window.stationDeliveryPanelInfoText.y + 80 + Math.round(panelH * 0.03);
for (var i = 0; i < window.resourceLabelOrder.length; i++) {
var resObj = window.resourceLabelOrder[i];
var req = window.stationDeliveryState.requests[resObj.origIdx];
var delivered = window.stationDeliveryState.delivered[resObj.origIdx];
var label = new Text2(resObj.name + ": " + delivered + " / " + req, {
size: labelFontSize,
fill: 0xffffff,
align: "left"
});
label.anchor.set(0, 0.5);
label.x = px - panelW / 2 + 60;
label.y = startY + i * rowH;
window.stationDeliveryLabels.push(label);
// Teslim Et button
var teslimBtn = new Text2("Teslim Et", {
size: panelBtnFontSize,
fill: 0x00ff99,
align: "center"
});
teslimBtn.anchor.set(0.5, 0.5);
teslimBtn.x = px + 220;
teslimBtn.y = label.y;
teslimBtn._stationResIdx = resObj.origIdx;
window.stationDeliveryDeliverBtns.push(teslimBtn);
}
// Bonus info
window.stationDeliveryPanelBonusText = new Text2("Tüm istekler tamamlanınca +" + window.stationDeliveryState.bonus + "% bonus fiyattan satılır.", {
size: bonusFontSize,
fill: 0xffff00,
align: "center"
});
window.stationDeliveryPanelBonusText.anchor.set(0.5, 0);
window.stationDeliveryPanelBonusText.x = px;
window.stationDeliveryPanelBonusText.y = startY + rowH * 10 + 30;
// Teslimatı Tamamla (ödül al) butonu
window.stationDeliveryPanelClaimBtn = new Text2("Tümünü Teslim Et & Ödülü Al", {
size: claimBtnFontSize,
fill: 0xffcc00,
align: "center"
});
window.stationDeliveryPanelClaimBtn.anchor.set(0.5, 0.5);
window.stationDeliveryPanelClaimBtn.x = px;
window.stationDeliveryPanelClaimBtn.y = window.stationDeliveryPanelBonusText.y + 90;
// Add to game
game.addChild(window.stationDeliveryPanelBG);
game.addChild(window.stationDeliveryPanelTitle);
game.addChild(window.stationDeliveryPanelInfoText);
game.addChild(window.stationDeliveryPanelCloseBtn);
for (var i = 0; i < window.stationDeliveryLabels.length; i++) game.addChild(window.stationDeliveryLabels[i]);
for (var i = 0; i < window.stationDeliveryDeliverBtns.length; i++) game.addChild(window.stationDeliveryDeliverBtns[i]);
game.addChild(window.stationDeliveryPanelBonusText);
game.addChild(window.stationDeliveryPanelClaimBtn);
window.stationDeliveryPanel = true;
};
window.closeStationDeliveryPanel = function () {
if (!window.stationDeliveryPanel) return;
if (window.stationDeliveryPanelBG && window.stationDeliveryPanelBG.parent) window.stationDeliveryPanelBG.parent.removeChild(window.stationDeliveryPanelBG);
if (window.stationDeliveryPanelTitle && window.stationDeliveryPanelTitle.parent) window.stationDeliveryPanelTitle.parent.removeChild(window.stationDeliveryPanelTitle);
if (window.stationDeliveryPanelInfoText && window.stationDeliveryPanelInfoText.parent) window.stationDeliveryPanelInfoText.parent.removeChild(window.stationDeliveryPanelInfoText);
if (window.stationDeliveryPanelCloseBtn && window.stationDeliveryPanelCloseBtn.parent) window.stationDeliveryPanelCloseBtn.parent.removeChild(window.stationDeliveryPanelCloseBtn);
if (window.stationDeliveryLabels) for (var i = 0; i < window.stationDeliveryLabels.length; i++) if (window.stationDeliveryLabels[i] && window.stationDeliveryLabels[i].parent) window.stationDeliveryLabels[i].parent.removeChild(window.stationDeliveryLabels[i]);
if (window.stationDeliveryDeliverBtns) for (var i = 0; i < window.stationDeliveryDeliverBtns.length; i++) if (window.stationDeliveryDeliverBtns[i] && window.stationDeliveryDeliverBtns[i].parent) window.stationDeliveryDeliverBtns[i].parent.removeChild(window.stationDeliveryDeliverBtns[i]);
if (window.stationDeliveryPanelBonusText && window.stationDeliveryPanelBonusText.parent) window.stationDeliveryPanelBonusText.parent.removeChild(window.stationDeliveryPanelBonusText);
if (window.stationDeliveryPanelClaimBtn && window.stationDeliveryPanelClaimBtn.parent) window.stationDeliveryPanelClaimBtn.parent.removeChild(window.stationDeliveryPanelClaimBtn);
window.stationDeliveryPanel = null;
window.stationDeliveryPanelBG = null;
window.stationDeliveryPanelTitle = null;
window.stationDeliveryPanelInfoText = null;
window.stationDeliveryPanelCloseBtn = null;
window.stationDeliveryLabels = null;
window.stationDeliveryDeliverBtns = null;
window.stationDeliveryPanelBonusText = null;
window.stationDeliveryPanelClaimBtn = null;
};
// --- GAME TIME LABEL ---
// Track game start time in ticks
var gameStartTick = LK.ticks;
var gameTimeText = new Text2('Game Time: 0:00', {
size: unifiedFontSize,
fill: 0xcccccc
});
gameTimeText.anchor.set(0, 0);
gameTimeText.x = coinText.x + coinText.width + 40;
gameTimeText.y = coinText.y;
LK.gui.topLeft.addChild(gameTimeText);
// Add an image below the Game Time label
if (!window.gameTimeImage) {
// Use an existing image asset, e.g. 'teslimEtBtnBg' as a placeholder
// Move the Global Panel image and button to the row above the station image
var imgScale = 0.7;
var imgAsset = LK.getAsset('teslimEtBtnBg', {
anchorX: 1,
anchorY: 1,
scaleX: imgScale,
scaleY: imgScale
});
// Place the image at the same x as the stationDeliveryBtnImage, but 1 row above it
// If stationDeliveryBtnImage exists, align to it
var refImg = window.stationDeliveryBtnImage;
if (refImg) {
imgAsset.x = refImg.x;
imgAsset.y = refImg.y - refImg.height; // 1 row above station image
} else {
// fallback: 10% right from left edge, and 10px below the Game Time label
imgAsset.x = Math.round(2048 * 0.10);
imgAsset.y = gameTimeText.y + gameTimeText.height + 10;
}
window.gameTimeImage = imgAsset;
LK.gui.bottomRight.addChild(window.gameTimeImage);
// --- Add a new independent image file at the position 2 rows above Hammadde Takası (Resource Trade) image ---
// Remove the previously created image if it exists
if (window.resourceTradePanelImage && window.resourceTradePanelImage.parent) {
window.resourceTradePanelImage.parent.removeChild(window.resourceTradePanelImage);
window.resourceTradePanelImage = null;
}
// Create a new independent image at the same position (now 1 row above Hammadde Takası image)
if (!window.resourceTradePanelIndependentImage) {
var independentImgScale = 0.7;
var independentImgAsset = LK.getAsset('resourceTradePanelIndependentCus', {
anchorX: 1,
anchorY: 1,
scaleX: independentImgScale,
scaleY: independentImgScale
});
// Place 1 row above the Hammadde Takası (Resource Trade) image
independentImgAsset.x = imgAsset.x;
independentImgAsset.y = imgAsset.y - imgAsset.height * 1;
window.resourceTradePanelIndependentImage = independentImgAsset;
LK.gui.bottomRight.addChild(independentImgAsset);
// Move the Hammadde Stoğu panel button (tap area) 2 rows above the image, image stays fixed
if (!window.resourceTradePanelIndependentBtn) {
var btn = new Text2("", {
size: 1,
fill: 0xffffff,
align: "center"
});
btn.anchor.set(1, 1);
btn.x = independentImgAsset.x;
btn.y = independentImgAsset.y - independentImgAsset.height * 2; // 2 rows above the image
btn.width = independentImgAsset.width;
btn.height = independentImgAsset.height;
btn.alpha = 0; // fully transparent, but still receives taps
window.resourceTradePanelIndependentBtn = btn;
LK.gui.bottomRight.addChild(btn);
}
}
// Add a transparent button area exactly the size and position of the image for Global Market
var marketBtn = new Text2("Global Market", {
size: 1,
fill: 0xffffff,
align: "center"
});
marketBtn.anchor.set(1, 1);
marketBtn.x = imgAsset.x;
// Move the button area 2 rows (imgAsset.height * 2) above the image, image stays fixed
marketBtn.y = imgAsset.y - imgAsset.height * 2;
// Grow the button area 10% downward and shrink it 5% from the top
marketBtn.width = imgAsset.width;
marketBtn.height = imgAsset.height * 1.10 * 0.95; // first grow 10%, then shrink 5% from top
marketBtn.alpha = 0; // fully transparent, but still receives taps
window.globalMarketBtn = marketBtn;
LK.gui.bottomRight.addChild(marketBtn);
}
// --- RESOURCE TRADE PANEL STATE ---
if (!window.resourceTradePanelState) {
// 10 hammadde için değerler (1-10 arası, rastgele başlat)
window.resourceTradeValues = [];
for (var i = 0; i < 10; i++) {
window.resourceTradeValues.push(1 + Math.floor(Math.random() * 10));
}
window.resourceTradePanelState = {
open: false,
lastValueUpdateTick: LK.ticks
};
}
// Timer: her 5 saniyede bir (300 tick) değerleri değiştir
if (!window._resourceTradeValueTimer) {
window._resourceTradeValueTimer = LK.setInterval(function () {
if (!window.resourceTradeValues) return;
for (var i = 0; i < window.resourceTradeValues.length; i++) {
// Değeri -3/+3 arası değiştir, 1-10 aralığında tut
var delta = Math.floor(Math.random() * 7) - 3;
window.resourceTradeValues[i] = Math.max(1, Math.min(10, window.resourceTradeValues[i] + delta));
}
// Panel açıksa UI güncelle
if (window.resourceTradePanelState && window.resourceTradePanelState.open && typeof window.updateResourceTradePanel === "function") {
window.updateResourceTradePanel();
}
}, 5000);
}
// Resource UI: create 10 vertically stacked resource labels, left-aligned
// Sort resourceTypes by name length descending, keep original index for mapping to playerResources
var resourceTypes = ['Metal', 'Energy', 'Crystal', 'Gas', 'Ice', 'Uranium', 'Silicon', 'Carbon', 'Plasma', 'Antimatter'];
var resourceTypeObjs = [];
for (var i = 0; i < resourceTypes.length; i++) {
resourceTypeObjs.push({
name: resourceTypes[i],
origIdx: i
});
}
resourceTypeObjs.sort(function (a, b) {
// Sort by name length descending, then alphabetically for ties
if (b.name.length !== a.name.length) return b.name.length - a.name.length;
return a.name.localeCompare(b.name);
});
window.resourceLabels = [];
window.resourceLabelOrder = resourceTypeObjs; // Save for updateUI
var resourceIconMargin = 8;
var resourceLabelStartY = Math.round(2732 * 0.05); // 5% down from the top
for (var i = 0; i < resourceTypeObjs.length; i++) {
var label = new Text2(resourceTypeObjs[i].name + ': 0', {
size: unifiedFontSize,
fill: 0xFFFFFF
});
label.anchor.set(0, 0);
label.x = 20; // flush to left edge, but leave margin for menu icon
label.y = resourceLabelStartY + i * (unifiedFontSize + resourceIconMargin);
// Do NOT add to GUI, so resource stock text is hidden on main screen
// LK.gui.topLeft.addChild(label);
window.resourceLabels.push(label);
}
// --- RESOURCE TRADE PANEL LOGIC ---
window.openResourceTradePanel = function () {
if (window.resourceTradePanelState.open) return;
window.resourceTradePanelState.open = true;
// Increase font size by 2 for all panel texts/buttons
var panelFontSize = unifiedFontSize + 2;
var panelBtnFontSize = panelFontSize;
var labelFontSize = panelFontSize;
var closeBtnFontSize = panelFontSize;
var infoFontSize = panelFontSize;
var titleFontSize = panelFontSize;
// Panel boyutları ve konum (resize for larger text/buttons)
var rowH = 80 + 8;
var panelW = 1200 + 120;
var panelH = 1200 + 2 * rowH;
var px = 1024,
py = 900;
// Panel BG
window.resourceTradePanelBG = LK.getAsset('resource', {
anchorX: 0.5,
anchorY: 0.5,
x: px,
y: py,
scaleX: panelW / 40,
scaleY: panelH / 40,
tint: 0x223355,
alpha: 0.97
});
// Başlık
window.resourceTradePanelTitle = new Text2("Hammadde Takası", {
size: titleFontSize,
fill: 0x00ffcc,
align: "center"
});
window.resourceTradePanelTitle.anchor.set(0.5, 0);
window.resourceTradePanelTitle.x = px;
window.resourceTradePanelTitle.y = py - panelH / 2 + 40;
// Bilgi yazısı
window.resourceTradePanelInfoText = new Text2("Elinizdeki hammaddeleri takas edebilirsiniz.\nHer hammaddenin değeri 5-30 arası değişir ve her 5 saniyede güncellenir.", {
size: infoFontSize,
fill: 0xffffff,
align: "center"
});
window.resourceTradePanelInfoText.anchor.set(0.5, 0);
window.resourceTradePanelInfoText.x = px;
window.resourceTradePanelInfoText.y = window.resourceTradePanelTitle.y + 60;
// Kapat butonu
window.resourceTradePanelCloseBtn = new Text2("Kapat", {
size: unifiedFontSize + 4,
// 2 font larger than Coins
fill: 0xff4444,
align: "center"
});
window.resourceTradePanelCloseBtn.anchor.set(0.5, 0.5);
window.resourceTradePanelCloseBtn.x = px;
window.resourceTradePanelCloseBtn.y = window.resourceTradePanelTitle.y - 110; // further above title
// Hammadde satırları ve butonları
window.resourceTradeLabels = [];
window.resourceTradeSellBtns = [];
window.resourceTradeSellAllBtns = [];
window.resourceTradeBuyBtns = [];
var startY = window.resourceTradePanelInfoText.y + 80 + rowH; // move all rows down by 1 row
for (var i = 0; i < window.resourceLabelOrder.length; i++) {
var resObj = window.resourceLabelOrder[i];
var idx = resObj.origIdx;
var label = new Text2(resObj.name + ": " + (playerResources[idx] || 0) + " | Değer: " + (window.resourceTradeValues ? window.resourceTradeValues[idx] : 0), {
size: labelFontSize,
fill: 0xffffff,
align: "left"
});
label.anchor.set(0, 0.5);
label.x = px - panelW / 2 + 60;
label.y = startY + i * rowH;
window.resourceTradeLabels.push(label);
// Sat butonu
var sellBtn = new Text2("Sat", {
size: panelBtnFontSize,
fill: 0x00ff99,
align: "center"
});
sellBtn.anchor.set(0.5, 0.5);
sellBtn.x = px + 220;
sellBtn.y = label.y;
sellBtn._resourceIdx = idx;
window.resourceTradeSellBtns.push(sellBtn);
// Tümünü Sat butonu
var sellAllBtn = new Text2("Tümünü Sat", {
size: panelBtnFontSize,
fill: 0x00cc99,
align: "center"
});
sellAllBtn.anchor.set(0.5, 0.5);
sellAllBtn.x = px + 400;
sellAllBtn.y = label.y;
sellAllBtn._resourceIdx = idx;
window.resourceTradeSellAllBtns.push(sellAllBtn);
// Al butonu
var buyBtn = new Text2("Al", {
size: panelBtnFontSize,
fill: 0x0099ff,
align: "center"
});
buyBtn.anchor.set(0.5, 0.5);
buyBtn.x = px + 580;
buyBtn.y = label.y;
buyBtn._resourceIdx = idx;
window.resourceTradeBuyBtns.push(buyBtn);
}
// Add to game
game.addChild(window.resourceTradePanelBG);
game.addChild(window.resourceTradePanelTitle);
game.addChild(window.resourceTradePanelInfoText);
game.addChild(window.resourceTradePanelCloseBtn);
for (var i = 0; i < window.resourceTradeLabels.length; i++) game.addChild(window.resourceTradeLabels[i]);
for (var i = 0; i < window.resourceTradeSellBtns.length; i++) game.addChild(window.resourceTradeSellBtns[i]);
for (var i = 0; i < window.resourceTradeSellAllBtns.length; i++) game.addChild(window.resourceTradeSellAllBtns[i]);
for (var i = 0; i < window.resourceTradeBuyBtns.length; i++) game.addChild(window.resourceTradeBuyBtns[i]);
// Panel güncelleme fonksiyonu
window.updateResourceTradePanel = function () {
for (var i = 0; i < window.resourceLabelOrder.length; i++) {
var resObj = window.resourceLabelOrder[i];
var idx = resObj.origIdx;
if (window.resourceTradeLabels[i]) {
window.resourceTradeLabels[i].setText(resObj.name + ": " + (playerResources[idx] || 0) + " | Değer: " + (window.resourceTradeValues ? window.resourceTradeValues[idx] : 0));
}
}
};
window.updateResourceTradePanel();
};
window.closeResourceTradePanel = function () {
if (!window.resourceTradePanelState.open) return;
window.resourceTradePanelState.open = false;
if (window.resourceTradePanelBG && window.resourceTradePanelBG.parent) window.resourceTradePanelBG.parent.removeChild(window.resourceTradePanelBG);
if (window.resourceTradePanelTitle && window.resourceTradePanelTitle.parent) window.resourceTradePanelTitle.parent.removeChild(window.resourceTradePanelTitle);
if (window.resourceTradePanelInfoText && window.resourceTradePanelInfoText.parent) window.resourceTradePanelInfoText.parent.removeChild(window.resourceTradePanelInfoText);
if (window.resourceTradePanelCloseBtn && window.resourceTradePanelCloseBtn.parent) window.resourceTradePanelCloseBtn.parent.removeChild(window.resourceTradePanelCloseBtn);
if (window.resourceTradeLabels) for (var i = 0; i < window.resourceTradeLabels.length; i++) if (window.resourceTradeLabels[i] && window.resourceTradeLabels[i].parent) window.resourceTradeLabels[i].parent.removeChild(window.resourceTradeLabels[i]);
if (window.resourceTradeSellBtns) for (var i = 0; i < window.resourceTradeSellBtns.length; i++) if (window.resourceTradeSellBtns[i] && window.resourceTradeSellBtns[i].parent) window.resourceTradeSellBtns[i].parent.removeChild(window.resourceTradeSellBtns[i]);
if (window.resourceTradeSellAllBtns) for (var i = 0; i < window.resourceTradeSellAllBtns.length; i++) if (window.resourceTradeSellAllBtns[i] && window.resourceTradeSellAllBtns[i].parent) window.resourceTradeSellAllBtns[i].parent.removeChild(window.resourceTradeSellAllBtns[i]);
if (window.resourceTradeBuyBtns) for (var i = 0; i < window.resourceTradeBuyBtns.length; i++) if (window.resourceTradeBuyBtns[i] && window.resourceTradeBuyBtns[i].parent) window.resourceTradeBuyBtns[i].parent.removeChild(window.resourceTradeBuyBtns[i]);
window.resourceTradePanelBG = null;
window.resourceTradePanelTitle = null;
window.resourceTradePanelInfoText = null;
window.resourceTradePanelCloseBtn = null;
window.resourceTradeLabels = null;
window.resourceTradeSellBtns = null;
window.resourceTradeSellAllBtns = null;
window.resourceTradeBuyBtns = null;
};
var healthText = new Text2('Health: 100/100', {
size: unifiedFontSize,
fill: 0x00FF00
});
healthText.anchor.set(0.5, 0);
healthText._isHealthBar = true; // Mark for tap detection
LK.gui.top.addChild(healthText);
var shieldText = new Text2('Shield: 50/50', {
size: unifiedFontSize,
fill: 0x0088FF
});
shieldText.anchor.set(0.5, 0);
shieldText.y = 60;
LK.gui.top.addChild(shieldText);
// --- Add waveText and expText UI for wave/level display ---
// --- REPAIR PANEL WARNING SUPPRESSION ---
// When repair panel is closed, set a suppression timer for 30 seconds (1800 ticks)
if (window.repairPanel && !window._repairPanelSuppressUntil) {
window._repairPanelSuppressUntil = LK.ticks + 1800;
}
// (removed duplicate handler, see main game.down below)
var waveText = new Text2('Wave: 1', {
size: unifiedFontSize,
fill: 0xffffff
});
waveText.anchor.set(0.5, 0);
waveText.x = 1024;
waveText.y = 60; // Move down to make space for market button
LK.gui.top.addChild(waveText);
var expText = new Text2('Level: 1 EXP: 0/10', {
size: unifiedFontSize,
fill: 0xffffff
});
expText.anchor.set(0.5, 0);
expText.x = 1024;
expText.y = 70;
LK.gui.top.addChild(expText);
// No wave, minimap, exp, or coordinate UI in this version
// Create joystick
joystickBase = game.addChild(LK.getAsset('joystickBase', {
anchorX: 0.5,
anchorY: 0.5,
x: 300,
y: 2432
}));
joystickBase.alpha = 0.5;
joystickHandle = game.addChild(LK.getAsset('joystickHandle', {
anchorX: 0.5,
anchorY: 0.5,
x: 300,
y: 2432
}));
joystickHandle.alpha = 0.7;
// Create ship
ship = game.addChild(new Ship());
ship.x = 1024;
ship.y = 1366;
// Add health bar to ship
ship._healthBar = new HealthBar();
ship._healthBar.set({
maxValue: function maxValue() {
return ship.maxHealth;
},
getValueFn: function getValueFn() {
return ship.health;
},
getMaxFn: function getMaxFn() {
return ship.maxHealth;
},
width: 80,
height: 12
});
ship._healthBar.y = -70;
ship.addChild(ship._healthBar);
// Start background music
LK.playMusic('bgmusic');
// Initialize star field (increased by 50%) and make them colorful
for (var i = 0; i < 135; i++) {
// 90 * 1.5 = 135
spawnStar(true); // pass true to enable colorful stars
}
// Spawn more map elements at start (20% more)
for (var i = 0; i < 6; i++) {
// was 5, now 6
spawnNPC();
}
for (var i = 0; i < 6; i++) {
// was 5, now 6
spawnPirate();
}
for (var i = 0; i < 4; i++) {
// was 5, now 4 (20% reduction)
spawnAsteroid();
}
// Helper functions
function spawnStar(colorful) {
var star = new Star();
// If colorful is true, assign a random color
if (colorful) {
// Pick a random color from a vibrant palette
var palette = [0xffe066,
// yellow
0xff66cc,
// pink
0x66ffcc,
// aqua
0x66ccff,
// blue
0xcc66ff,
// purple
0xff6666,
// red
0x66ff66,
// green
0xffffff,
// white
0xffcc66,
// orange
0x66ffff // cyan
];
var color = palette[Math.floor(Math.random() * palette.length)];
if (star.children && star.children.length > 0 && star.children[0]) {
star.children[0].tint = color;
}
}
// Spawn at a random position within a large area around the ship
var radius = 1800 + Math.random() * 1200; // 1800-3000 px from ship
var angle = Math.random() * Math.PI * 2;
star.x = ship.x + Math.cos(angle) * radius;
star.y = ship.y + Math.sin(angle) * radius;
stars.push(star);
game.addChild(star);
}
function spawnNPC() {
var npc = new NPC();
// Spawn from edges of visible area
var edge = Math.floor(Math.random() * 4);
switch (edge) {
case 0:
// Top
npc.x = ship.x + (Math.random() - 0.5) * 2000;
npc.y = ship.y - 1500;
break;
case 1:
// Right
npc.x = ship.x + 1500;
npc.y = ship.y + (Math.random() - 0.5) * 2000;
break;
case 2:
// Bottom
npc.x = ship.x + (Math.random() - 0.5) * 2000;
npc.y = ship.y + 1500;
break;
case 3:
// Left
npc.x = ship.x - 1500;
npc.y = ship.y + (Math.random() - 0.5) * 2000;
break;
}
npc.baseY = npc.y;
// --- Set NPC level and health to match pirate scaling ---
var minLevel = 1 + waveNumber * 2;
var maxLevel = minLevel + 2;
npc.level = minLevel + Math.floor(Math.random() * (maxLevel - minLevel + 1));
npc.health = 100 + (npc.level - 1) * 10;
// Add health bar to NPC (for defend/hunt/escort/delivery/explore)
npc._healthBar = new HealthBar();
npc._healthBar.set({
maxValue: function maxValue() {
return npc.health !== undefined ? npc.health : 100;
},
getValueFn: function getValueFn() {
return npc.health !== undefined ? npc.health : 100;
},
getMaxFn: function getMaxFn() {
return 100 + (npc.level - 1) * 10;
},
width: 60,
height: 10
});
npc._healthBar.y = -60;
npc.addChild(npc._healthBar);
npcs.push(npc);
game.addChild(npc);
}
function spawnPirate() {
var pirate = new Pirate();
// Spawn from edges of visible area
var edge = Math.floor(Math.random() * 4);
switch (edge) {
case 0:
// Top
pirate.x = ship.x + (Math.random() - 0.5) * 1800;
pirate.y = ship.y - 1400;
break;
case 1:
// Right
pirate.x = ship.x + 1400;
pirate.y = ship.y + (Math.random() - 0.5) * 1800;
break;
case 2:
// Bottom
pirate.x = ship.x + (Math.random() - 0.5) * 1800;
pirate.y = ship.y + 1400;
break;
case 3:
// Left
pirate.x = ship.x - 1400;
pirate.y = ship.y + (Math.random() - 0.5) * 1800;
break;
}
// Set pirate level and scale stats based on wave
// Level range: wave 1 => 1-3, wave 2 => 3-5, wave 3 => 5-7, etc.
var minLevel = 1 + waveNumber * 2;
var maxLevel = minLevel + 2;
pirate.level = minLevel + Math.floor(Math.random() * (maxLevel - minLevel + 1));
pirate.health = 30 + (pirate.level - 1) * 10;
pirate.damage = 5 + Math.floor((pirate.level - 1) * 1.5);
pirate.defense = 2 + Math.floor((pirate.level - 1) * 1.2);
// Add health bar to pirate
pirate._healthBar = new HealthBar();
pirate._healthBar.set({
maxValue: function maxValue() {
return pirate.health > 0 ? pirate.health : 0;
},
getValueFn: function getValueFn() {
return pirate.health > 0 ? pirate.health : 0;
},
getMaxFn: function getMaxFn() {
return 30 + waveNumber * 10;
},
width: 60,
height: 10
});
pirate._healthBar.y = -60;
pirate.addChild(pirate._healthBar);
pirates.push(pirate);
game.addChild(pirate);
}
function spawnAsteroid() {
var asteroid = new Asteroid();
var edge = Math.floor(Math.random() * 4);
switch (edge) {
case 0:
asteroid.x = ship.x + (Math.random() - 0.5) * 2200;
asteroid.y = ship.y - 1600;
break;
case 1:
asteroid.x = ship.x + 1600;
asteroid.y = ship.y + (Math.random() - 0.5) * 2200;
break;
case 2:
asteroid.x = ship.x + (Math.random() - 0.5) * 2200;
asteroid.y = ship.y + 1600;
break;
case 3:
asteroid.x = ship.x - 1600;
asteroid.y = ship.y + (Math.random() - 0.5) * 2200;
break;
}
// Add health bar to asteroid
asteroid._healthBar = new HealthBar();
asteroid._healthBar.set({
maxValue: function maxValue() {
return asteroid.health;
},
getValueFn: function getValueFn() {
return asteroid.health;
},
getMaxFn: function getMaxFn() {
return 50;
},
width: 50,
height: 8
});
asteroid._healthBar.y = -50;
asteroid.addChild(asteroid._healthBar);
asteroids.push(asteroid);
game.addChild(asteroid);
}
// No upgrade stations in this version
// No trade stations in this version
function createExplosion(x, y) {
for (var i = 0; i < 8; i++) {
var particle = LK.getAsset('explosion', {
anchorX: 0.5,
anchorY: 0.5,
x: x,
y: y
});
particle.vx = (Math.random() - 0.5) * 10;
particle.vy = (Math.random() - 0.5) * 10;
particle.life = 30;
explosions.push(particle);
game.addChild(particle);
}
}
// No black holes or wormholes in this version
function updateUI() {
coinText.setText('Coins: ' + playerCoins);
// Keep playerMetal/playerEnergy in sync with playerResources
playerMetal = playerResources[0];
playerEnergy = playerResources[1];
// Use sorted resource label order for display
if (window.resourceLabels && window.resourceLabelOrder && window.resourceLabels.length === window.resourceLabelOrder.length) {
for (var i = 0; i < window.resourceLabelOrder.length; i++) {
var resObj = window.resourceLabelOrder[i];
window.resourceLabels[i].setText(resObj.name + ': ' + (playerResources[resObj.origIdx] || 0));
}
}
// (No market price display)
var healthPercent = Math.round(ship.health / ship.maxHealth * 100);
healthText.setText('Health: %' + healthPercent);
var shieldPercent = Math.round(ship.shield / ship.maxShield * 100);
shieldText.setText('Shield: %' + shieldPercent);
// Restore wave and exp UI
if (typeof waveText !== "undefined") {
waveText.setText('Wave: ' + (waveNumber + 1));
}
if (typeof expText !== "undefined") {
expText.setText('Level: ' + playerLevel + ' EXP: ' + playerEXP + '/' + expToNext(playerLevel));
}
waveText.setText('Wave: ' + (waveNumber + 1));
expText.setText('Level: ' + playerLevel + ' EXP: ' + playerEXP + '/' + expToNext(playerLevel));
// Show player level/exp in GUI (top right, above repText)
if (!window.levelText) {
window.levelText = new Text2('Seviye: ' + playerLevel + ' EXP: ' + playerEXP + '/' + expToNext(playerLevel), {
size: unifiedFontSize,
fill: 0xffffff
});
window.levelText.anchor.set(1, 0);
window.levelText.x = -20;
window.levelText.y = 20; // moved up by one row (40px)
LK.gui.topRight.addChild(window.levelText);
}
window.levelText.setText('Seviye: ' + playerLevel + ' EXP: ' + playerEXP + '/' + expToNext(playerLevel));
// Update player level/exp in top right
if (window.levelText) {
window.levelText.setText('Seviye: ' + playerLevel + ' EXP: ' + playerEXP + '/' + expToNext(playerLevel));
}
// Update health text color
if (ship.health > 60) {
healthText.fill = 0x00ff00;
} else if (ship.health > 30) {
healthText.fill = 0xffff00;
} else {
healthText.fill = 0xff0000;
}
// Update shield text color
if (ship.shield > 30) {
shieldText.fill = 0x0088ff;
} else if (ship.shield > 10) {
shieldText.fill = 0xffff00;
} else {
shieldText.fill = 0xff0000;
}
storage.playerLevel = playerLevel;
storage.playerEXP = playerEXP;
}
function saveProgress() {
storage.coins = playerCoins;
var resourceKeys = ['metal', 'energy', 'crystal', 'gas', 'ice', 'uranium', 'silicon', 'carbon', 'plasma', 'antimatter'];
for (var i = 0; i < resourceKeys.length; i++) {
storage[resourceKeys[i]] = playerResources[i] || 0;
}
// Keep playerMetal/playerEnergy in sync with playerResources
playerMetal = playerResources[0];
playerEnergy = playerResources[1];
storage.questsCompleted = questsCompleted;
}
// Event handlers
game.down = function (x, y, obj) {
// --- GLOBAL MARKET BUTTON HANDLER (exact image area) ---
if (window.globalMarketBtn && window.globalMarketBtn.parent) {
var btn = window.globalMarketBtn;
var bx = btn.x,
by = btn.y;
var bw = btn.width || 320,
bh = btn.height || 80;
// LK.gui.bottomRight is anchored at (1,1), so x,y negative from bottom right
// The area is anchored at (1,1), so its (x,y) is the bottom right corner of the area
// So the area covers (bx-bw, by-bh) to (bx, by)
if (x > 2048 + bx - bw && x < 2048 + bx && y > 2732 + by - bh && y < 2732 + by) {
window.openResourceTradePanel();
return;
}
}
// --- RESOURCE TRADE PANEL INDEPENDENT BUTTON HANDLER ---
// If the independent button exists, check tap
if (window.resourceTradePanelIndependentBtn && window.resourceTradePanelIndependentBtn.parent) {
var btn = window.resourceTradePanelIndependentBtn;
var bx = btn.x,
by = btn.y;
var bw = btn.width,
bh = btn.height;
// LK.gui.bottomRight is anchored at (1,1), so x,y negative from bottom right
// The area is anchored at (1,1), so its (x,y) is the bottom right corner of the area
// So the area covers (bx-bw, by-bh) to (bx, by)
if (x > 2048 + bx - bw && x < 2048 + bx && y > 2732 + by - bh && y < 2732 + by) {
// Open 'Hammadde Stoğu' panel
if (typeof window.openResourceStockPanel === "function") {
window.openResourceStockPanel();
} else {
// Fallback: show a simple panel with player's resource stock
if (window._resourceStockPanel) return;
var panelW = 900,
panelH = 900;
var px = 1024,
py = 900;
// Increase font size by 2 for all panel texts/buttons
var panelFontSize = unifiedFontSize + 2;
var labelFontSize = panelFontSize;
var closeBtnFontSize = panelFontSize;
var titleFontSize = panelFontSize;
// Resize panel background to fit enlarged text/buttons
var rowH = 70 + 8;
var panelW = 900 + 120;
var panelH = 900 + 2 * rowH;
var bg = LK.getAsset('resource', {
anchorX: 0.5,
anchorY: 0.5,
x: px,
y: py,
scaleX: panelW / 40,
scaleY: panelH / 40,
tint: 0x223355,
alpha: 0.97
});
var title = new Text2("Hammadde Stoğu", {
size: titleFontSize,
fill: 0x00ffcc,
align: "center"
});
title.anchor.set(0.5, 0);
title.x = px;
title.y = py - panelH / 2 + 40;
// List resources
var labels = [];
var startY = title.y + 80;
for (var i = 0; i < window.resourceLabelOrder.length; i++) {
var resObj = window.resourceLabelOrder[i];
var idx = resObj.origIdx;
var label = new Text2(resObj.name + ": " + (playerResources[idx] || 0), {
size: labelFontSize,
fill: 0xffffff,
align: "left"
});
label.anchor.set(0, 0.5);
label.x = px - panelW / 2 + 60;
label.y = startY + i * rowH;
labels.push(label);
}
// Close button
var closeBtn = new Text2("Kapat", {
size: unifiedFontSize + 4,
// 2 font larger than Coins
fill: 0xff4444,
align: "center"
});
closeBtn.anchor.set(0.5, 0.5);
closeBtn.x = px;
closeBtn.y = title.y - 110; // above the title
// Add to game
game.addChild(bg);
game.addChild(title);
for (var i = 0; i < labels.length; i++) game.addChild(labels[i]);
game.addChild(closeBtn);
// Store refs for tap logic/cleanup
window._resourceStockPanel = {
bg: bg,
title: title,
labels: labels,
closeBtn: closeBtn
};
// Add close logic
closeBtn._isResourceStockCloseBtn = true;
}
return;
}
}
// --- RESOURCE TRADE PANEL HANDLER ---
if (window._resourceStockPanel && window._resourceStockPanel.closeBtn) {
var btn = window._resourceStockPanel.closeBtn;
var bx = btn.x,
by = btn.y;
var bw = btn.width || 300,
bh = btn.height || 80;
if (x > bx - bw / 2 && x < bx + bw / 2 && y > by - bh / 2 && y < by + bh / 2) {
// Remove all panel elements
if (window._resourceStockPanel.bg && window._resourceStockPanel.bg.parent) window._resourceStockPanel.bg.parent.removeChild(window._resourceStockPanel.bg);
if (window._resourceStockPanel.title && window._resourceStockPanel.title.parent) window._resourceStockPanel.title.parent.removeChild(window._resourceStockPanel.title);
if (window._resourceStockPanel.labels) for (var i = 0; i < window._resourceStockPanel.labels.length; i++) if (window._resourceStockPanel.labels[i] && window._resourceStockPanel.labels[i].parent) window._resourceStockPanel.labels[i].parent.removeChild(window._resourceStockPanel.labels[i]);
if (window._resourceStockPanel.closeBtn && window._resourceStockPanel.closeBtn.parent) window._resourceStockPanel.closeBtn.parent.removeChild(window._resourceStockPanel.closeBtn);
window._resourceStockPanel = null;
return;
}
}
if (window.resourceTradePanelState && window.resourceTradePanelState.open) {
// Close btn
if (window.resourceTradePanelCloseBtn) {
var bx = window.resourceTradePanelCloseBtn.x,
by = window.resourceTradePanelCloseBtn.y;
var bw = window.resourceTradePanelCloseBtn.width || 300,
bh = window.resourceTradePanelCloseBtn.height || 80;
if (x > bx - bw / 2 && x < bx + bw / 2 && y > by - bh / 2 && y < by + bh / 2) {
window.closeResourceTradePanel();
return;
}
}
// Sat btns
if (window.resourceTradeSellBtns) {
for (var i = 0; i < window.resourceTradeSellBtns.length; i++) {
var btn = window.resourceTradeSellBtns[i];
var bx = btn.x,
by = btn.y;
var bw = btn.width || 120,
bh = btn.height || 60;
if (x > bx - bw / 2 && x < bx + bw / 2 && y > by - bh / 2 && y < by + bh / 2) {
var idx = btn._resourceIdx;
var amount = playerResources[idx] || 0;
var value = window.resourceTradeValues ? window.resourceTradeValues[idx] : 0;
if (amount > 0 && value > 0) {
playerCoins += value * amount;
playerResources[idx] = 0;
btn.setText("Satıldı!");
btn.fill = 0x00ffcc;
if (window.updateResourceTradePanel) window.updateResourceTradePanel();
updateUI();
saveProgress();
} else {
btn.setText("Yok!");
btn.fill = 0xff4444;
}
// Reset label after short delay
(function (b, orig, origFill) {
LK.setTimeout(function () {
b.setText("Sat");
b.fill = 0x00ff99;
}, 700);
})(btn, "Sat", 0x00ff99);
return;
}
}
}
// Tümünü Sat btns
if (window.resourceTradeSellAllBtns) {
for (var i = 0; i < window.resourceTradeSellAllBtns.length; i++) {
var btn = window.resourceTradeSellAllBtns[i];
var bx = btn.x,
by = btn.y;
var bw = btn.width || 180,
bh = btn.height || 60;
if (x > bx - bw / 2 && x < bx + bw / 2 && y > by - bh / 2 && y < by + bh / 2) {
var idx = btn._resourceIdx;
var amount = playerResources[idx] || 0;
var value = window.resourceTradeValues ? window.resourceTradeValues[idx] : 0;
if (amount > 0 && value > 0) {
playerCoins += value * amount;
playerResources[idx] = 0;
btn.setText("Hepsi Satıldı!");
btn.fill = 0x00ffcc;
if (window.updateResourceTradePanel) window.updateResourceTradePanel();
updateUI();
saveProgress();
} else {
btn.setText("Yok!");
btn.fill = 0xff4444;
}
(function (b, orig, origFill) {
LK.setTimeout(function () {
b.setText("Tümünü Sat");
b.fill = 0x00cc99;
}, 700);
})(btn, "Tümünü Sat", 0x00cc99);
return;
}
}
}
// Al btns
if (window.resourceTradeBuyBtns) {
for (var i = 0; i < window.resourceTradeBuyBtns.length; i++) {
var btn = window.resourceTradeBuyBtns[i];
var bx = btn.x,
by = btn.y;
var bw = btn.width || 120,
bh = btn.height || 60;
if (x > bx - bw / 2 && x < bx + bw / 2 && y > by - bh / 2 && y < by + bh / 2) {
var idx = btn._resourceIdx;
var value = window.resourceTradeValues ? window.resourceTradeValues[idx] : 0;
// Satın alma miktarı: 1 (veya istenirse artırılabilir)
var buyAmount = 1;
var totalCost = value * buyAmount;
if (playerCoins >= totalCost && value > 0) {
playerCoins -= totalCost;
playerResources[idx] = (playerResources[idx] || 0) + buyAmount;
btn.setText("Alındı!");
btn.fill = 0x00ffcc;
if (window.updateResourceTradePanel) window.updateResourceTradePanel();
updateUI();
saveProgress();
} else {
btn.setText("Yetersiz coin!");
btn.fill = 0xff4444;
}
(function (b, orig, origFill) {
LK.setTimeout(function () {
b.setText("Al");
b.fill = 0x0099ff;
}, 700);
})(btn, "Al", 0x0099ff);
return;
}
}
}
// Block all other taps when panel is open
return;
}
// --- UZAY İSTASYONU TESLİMAT BUTTON HANDLER ---
// Handle tap on stationDeliveryBtnArea (transparent area, exactly image size)
if (window.stationDeliveryBtnArea && window.stationDeliveryBtnArea.parent) {
var btn = window.stationDeliveryBtnArea;
var bx = btn.x,
by = btn.y;
var bw = btn.width,
bh = btn.height;
// LK.gui.bottomRight is anchored at (1,1), so x,y negative from bottom right
// The area is anchored at (1,1), so its (x,y) is the bottom right corner of the area
// So the area covers (bx-bw, by-bh) to (bx, by)
if (x > 2048 + bx - bw && x < 2048 + bx && y > 2732 + by - bh && y < 2732 + by) {
window.openStationDeliveryPanel();
return;
}
}
// LK.gui.bottomRight is anchored at (1,1), so x,y negative from bottom right
if (window.stationDeliveryBtn && window.stationDeliveryBtn.parent) {
var btn = window.stationDeliveryBtn;
var bx = btn.x,
by = btn.y;
// Button is about 180x80 px, so check if x is within 200px of right edge and y within 300-480px of bottom
if (x > 2048 - 200 && y > 2732 - 300 && y < 2732 - 100) {
window.openStationDeliveryPanel();
return;
}
}
// --- UZAY İSTASYONU TESLİMAT PANEL HANDLER ---
if (window.stationDeliveryPanel) {
// Close btn
if (window.stationDeliveryPanelCloseBtn) {
var bx = window.stationDeliveryPanelCloseBtn.x,
by = window.stationDeliveryPanelCloseBtn.y;
var bw = window.stationDeliveryPanelCloseBtn.width || 300,
bh = window.stationDeliveryPanelCloseBtn.height || 80;
if (x > bx - bw / 2 && x < bx + bw / 2 && y > by - bh / 2 && y < by + bh / 2) {
window.closeStationDeliveryPanel();
return;
}
}
// Teslim Et btns
if (window.stationDeliveryDeliverBtns) {
for (var i = 0; i < window.stationDeliveryDeliverBtns.length; i++) {
var btn = window.stationDeliveryDeliverBtns[i];
var bx = btn.x,
by = btn.y;
var bw = btn.width || 120,
bh = btn.height || 60;
if (x > bx - bw / 2 && x < bx + bw / 2 && y > by - bh / 2 && y < by + bh / 2) {
var idx = btn._stationResIdx;
var req = window.stationDeliveryState.requests[idx];
var delivered = window.stationDeliveryState.delivered[idx];
var canDeliver = Math.min(playerResources[idx], req - delivered);
if (canDeliver > 0) {
playerResources[idx] -= canDeliver;
window.stationDeliveryState.delivered[idx] += canDeliver;
btn.setText("Teslim Edildi!");
btn.fill = 0x00ffcc;
// Update label
if (window.stationDeliveryLabels && window.stationDeliveryLabels[i]) {
window.stationDeliveryLabels[i].setText(window.resourceLabelOrder[i].name + ": " + window.stationDeliveryState.delivered[idx] + " / " + req);
}
updateUI();
saveProgress();
} else {
btn.setText("Yok!");
btn.fill = 0xff4444;
}
// Reset label after short delay
(function (b, orig, origFill) {
LK.setTimeout(function () {
b.setText(orig);
b.fill = origFill;
}, 700);
})(btn, "Teslim Et", 0x00ff99);
return;
}
}
}
// Teslimatı Tamamla (ödül al) butonu
if (window.stationDeliveryPanelClaimBtn) {
var btn = window.stationDeliveryPanelClaimBtn;
var bx = btn.x,
by = btn.y;
var bw = btn.width || 400,
bh = btn.height || 80;
if (x > bx - bw / 2 && x < bx + bw / 2 && y > by - bh / 2 && y < by + bh / 2) {
// Check if all delivered
var allDone = true;
for (var i = 0; i < 10; i++) {
if (window.stationDeliveryState.delivered[i] < window.stationDeliveryState.requests[i]) {
allDone = false;
break;
}
}
if (allDone && !window.stationDeliveryState.rewardClaimed) {
// Calculate total value (normal market price * delivered) * (1+bonus%)
var totalValue = 0;
for (var i = 0; i < 10; i++) {
var price = 1; // Market removed, use static price
totalValue += price * window.stationDeliveryState.requests[i];
}
var bonus = window.stationDeliveryState.bonus;
var reward = Math.round(totalValue * (1 + bonus / 100));
playerCoins += reward;
window.stationDeliveryState.rewardClaimed = true;
btn.setText("Ödül Alındı! +" + reward + " coin");
btn.fill = 0x00ffcc;
// Show floating label
var label = new Text2("İstasyon Teslimatı Tamamlandı!\n+" + reward + " coin", {
size: 48,
fill: 0xffcc00,
align: "center"
});
label.anchor.set(0.5, 0.5);
label.x = 1024;
label.y = 600;
game.addChild(label);
LK.setTimeout(function () {
if (label.parent) label.parent.removeChild(label);
}, 1800);
updateUI();
saveProgress();
} else if (window.stationDeliveryState.rewardClaimed) {
btn.setText("Zaten Alındı!");
btn.fill = 0x888888;
} else {
btn.setText("Eksik Teslimat!");
btn.fill = 0xff4444;
}
// Reset label after short delay
(function (b, orig, origFill) {
LK.setTimeout(function () {
b.setText("Tümünü Teslim Et & Ödülü Al");
b.fill = 0xffcc00;
}, 1200);
})(btn, "Tümünü Teslim Et & Ödülü Al", 0xffcc00);
return;
}
}
// Block all other taps when panel is open
return;
}
// --- RESET BUTTON HANDLER ---
if (game._resetBtn && game._resetBtn.parent) {
// Convert GUI coordinates for bottomRight
// LK.gui.bottomRight is anchored at (1,1) so x,y are negative from bottom right
var btn = game._resetBtn;
var bx = btn.x,
by = btn.y;
// Button is about 180x80 px, but let's use a safe area
// Since anchor is (1,1), bottom right, and x/y are negative from bottom right
// So, for a tap, check if x is within 200px of right edge and y within 100px of bottom
// LK.gui.bottomRight: x=0,y=0 is bottom right, so x,y negative
if (x > 2048 - 200 && y > 2732 - 100) {
// Clear all persistent storage
storage.coins = 0;
storage.metal = 0;
storage.energy = 0;
storage.crystal = 0;
storage.gas = 0;
storage.ice = 0;
storage.uranium = 0;
storage.silicon = 0;
storage.carbon = 0;
storage.plasma = 0;
storage.antimatter = 0;
storage.questsCompleted = 0;
storage.playerLevel = 1;
storage.playerEXP = 0;
// Optionally clear any other custom progress keys
// Show a quick feedback
btn.setText("Reset!");
btn.fill = 0x00ff99;
// Reload game (reset all progress)
LK.showGameOver();
return;
}
}
// --- MINI MAP BUTTON HANDLER ---
if (game._miniMapBtn && game._miniMapBtn.parent) {
// Mini map button is about 180x80 px, left of Reset
// x: 2048 - 400 to 2048 - 220, y: 2732 - 100 to 2732
if (x > 2048 - 400 && x < 2048 - 220 && y > 2732 - 100 && y < 2732) {
window._miniMapVisible = !window._miniMapVisible;
// If hiding, remove all mini map elements
if (!window._miniMapVisible && window._miniMapContainer && window._miniMapContainer.parent) {
window._miniMapContainer.parent.removeChild(window._miniMapContainer);
window._miniMapElements = [];
window._miniMapContainer = null;
}
// If showing, force a minimap update by calling the minimap overlay logic
if (window._miniMapVisible) {
// The minimap overlay is drawn in the main game loop, so we just need to trigger a redraw
// by setting _miniMapVisible = true. The next game.update will draw it.
// Optionally, we can force a redraw immediately by calling game.update() if needed.
if (typeof game.update === "function") {
game.update();
}
}
return;
}
}
// --- NPC ile savaş butonu handler ---
if (window.npcFightBtn) {
var bx = window.npcFightBtn.x,
by = window.npcFightBtn.y;
var bw = window.npcFightBtn.width || 400,
bh = window.npcFightBtn.height || 100;
// Accept generous tap area
if (x > bx - bw / 2 && x < bx + bw / 2 && y > by - bh / 2 && y < by + bh / 2) {
window.npcFightMode = !window.npcFightMode;
if (window.npcFightMode) {
window.npcFightBtn.setText("NPC Savaş: AÇIK");
window.npcFightBtn.fill = 0xff0000;
} else {
window.npcFightBtn.setText("NPC ile Savaş");
window.npcFightBtn.fill = 0xff4444;
}
return;
}
}
if (window.repairPanel && window.repairBtn && window.repairBtn.parent) {
// Check tap on repair button
var btn = window.repairBtn;
var bx = btn.x,
by = btn.y;
if (x > bx - 90 && x < bx + 90 && y > by - 40 && y < by + 40) {
// Try to repair
var costCoins = btn._repairCostCoins,
costMetal = btn._repairCostMetal,
costEnergy = btn._repairCostEnergy;
if (playerCoins >= costCoins && playerMetal >= costMetal && playerEnergy >= costEnergy) {
playerCoins -= costCoins;
playerMetal -= costMetal;
playerEnergy -= costEnergy;
ship.health = ship.maxHealth;
updateUI();
saveProgress();
// Show feedback
btn.setText("Tamir Edildi!");
btn.fill = 0x00ffcc;
// Remove panel after short delay
var expire = LK.ticks + 40;
var origUpdate = game.update;
game.update = function () {
if (LK.ticks > expire) {
if (window.repairPanel && window.repairPanel.parent) window.repairPanel.parent.removeChild(window.repairPanel);
if (window.repairText && window.repairText.parent) window.repairText.parent.removeChild(window.repairText);
if (window.repairBtn && window.repairBtn.parent) window.repairBtn.parent.removeChild(window.repairBtn);
if (window.cancelRepairBtn && window.cancelRepairBtn.parent) window.cancelRepairBtn.parent.removeChild(window.cancelRepairBtn);
window.repairPanel = null;
window.repairText = null;
window.repairBtn = null;
window.cancelRepairBtn = null;
game.update = origUpdate;
}
if (origUpdate) origUpdate.apply(game, arguments);
};
} else {
// Not enough resources
btn.setText("Yetersiz kaynak!");
btn.fill = 0xff4444;
}
return;
}
// Check tap on cancel button
var cbtn = window.cancelRepairBtn;
if (cbtn) {
var cbx = cbtn.x,
cby = cbtn.y;
if (x > cbx - 90 && x < cbx + 90 && y > cby - 40 && y < cby + 40) {
// Remove all repair panel elements, allow closing even if not repaired
if (window.repairPanel && window.repairPanel.parent) window.repairPanel.parent.removeChild(window.repairPanel);
if (window.repairText && window.repairText.parent) window.repairText.parent.removeChild(window.repairText);
if (window.repairBtn && window.repairBtn.parent) window.repairBtn.parent.removeChild(window.repairBtn);
if (window.cancelRepairBtn && window.cancelRepairBtn.parent) window.cancelRepairBtn.parent.removeChild(window.cancelRepairBtn);
window.repairPanel = null;
window.repairText = null;
window.repairBtn = null;
window.cancelRepairBtn = null;
window._showRepairPanel = false;
return;
}
}
}
// --- Health bar tap to show repair panel ---
if (healthText && healthText.parent && healthText._isHealthBar && ship.health < ship.maxHealth && ship.health > 0) {
// Get healthText bounds in screen coordinates
// healthText is anchored at (0.5, 0), at top center
// Let's estimate its bounds
var hx = healthText.x,
hy = healthText.y;
var hw = healthText.width || 300;
var hh = healthText.height || 60;
// Accept generous tap area
if (x > hx - hw / 2 && x < hx + hw / 2 && y > hy && y < hy + hh) {
window._showRepairPanel = true;
return;
}
}
// --- SHIP TAP: Show upgrade/can-buy-health panel ---
if (ship && ship.parent) {
// Ship is at (ship.x, ship.y), size is 80x100 (see asset)
var sx = ship.x,
sy = ship.y;
var sw = 80,
sh = 100;
// Accept generous tap area
if (x > sx - sw / 2 && x < sx + sw / 2 && y > sy - sh / 2 && y < sy + sh / 2) {
// Only show if not already shown
if (!window.shipUpgradePanel) {
// Panel background
// --- DYNAMIC PANEL SIZE BASED ON CONTENT ---
var upgBtnFont = unifiedFontSize;
var upgBtnWidth = 340;
var upgBtnHeight = 90;
var colSpacing = 80;
var colXOffset = upgBtnWidth / 2 + colSpacing / 2;
var upgBtnSpacingY = 140;
var numUpgradeRows = 4; // 3 upgrade rows + 1 buy health row
var panelContentHeight = 100 + numUpgradeRows * upgBtnSpacingY + 2 * upgBtnHeight; // title + upgrades + buy health + speed + some margin
var panelContentWidth = upgBtnWidth * 2 + colSpacing + 80; // two columns + spacing + margin
// Add extra for speed upgrade and close button
panelContentHeight += upgBtnSpacingY + 60; // speed upgrade + close btn margin
// Clamp min/max
var panelWidth = Math.max(700, Math.round(panelContentWidth));
var panelHeight = Math.max(340, Math.round(panelContentHeight));
var panel = LK.getAsset('resource', {
anchorX: 0.5,
anchorY: 0.5,
x: sx,
y: sy - 220,
scaleX: panelWidth / 40,
// asset is 40px wide
scaleY: panelHeight / 40,
// asset is 40px tall
tint: 0x224488
});
// Title
var titleFont = Math.round(62 * 1.1) - 3;
var title = new Text2("Yükseltmeler & Can Satın Al", {
size: titleFont,
fill: 0xffffff,
align: "center"
});
title.anchor.set(0.5, 0.5);
title.x = sx;
title.y = sy - 220 - panelHeight / 2 + 100;
// Upgrade buttons, dikeyde aralıklı ve panelin içine sığacak şekilde
var upgBtnY = title.y + 110;
var upgBtnSpacingY = 140;
// Paneldeki yazı ve butonların font boyutunu, Wave font boyutu ile aynı yap
var upgBtnFont = unifiedFontSize;
var upgBtnWidth = 340;
var upgBtnHeight = 90;
var colSpacing = 80;
var colXOffset = upgBtnWidth / 2 + colSpacing / 2;
// Normal upgrades
var upg1 = new Text2("Max Can +20\n(600 coin, 60 metal)", {
size: upgBtnFont,
fill: 0x00ff99,
align: "center"
});
upg1.anchor.set(0.5, 0.5);
upg1.x = sx - colXOffset;
upg1.y = upgBtnY;
upg1._isShipUpgradeBtn = true;
upg1._upgradeType = "maxHealth";
upg1._upgradeCost = {
coins: 600,
metal: 60,
energy: 0
};
var upg1x2 = new Text2("Max Can +20\n(1200 coin, 120 metal)", {
size: upgBtnFont,
fill: 0x00cc99,
align: "center"
});
upg1x2.anchor.set(0.5, 0.5);
upg1x2.x = sx + colXOffset;
upg1x2.y = upgBtnY;
upg1x2._isShipUpgradeBtn = true;
upg1x2._upgradeType = "maxHealth";
upg1x2._upgradeCost = {
coins: 1200,
metal: 120,
energy: 0
};
upg1x2._isDoubleCost = true;
var upg2 = new Text2("Max Kalkan +10\n(720 coin, 72 metal)", {
size: upgBtnFont,
fill: 0x00ccff,
align: "center"
});
upg2.anchor.set(0.5, 0.5);
upg2.x = sx - colXOffset;
upg2.y = upgBtnY + upgBtnSpacingY;
upg2._isShipUpgradeBtn = true;
upg2._upgradeType = "maxShield";
upg2._upgradeCost = {
coins: 720,
metal: 72,
energy: 0
};
var upg2x2 = new Text2("Max Kalkan +10\n(1440 coin, 144 metal)", {
size: upgBtnFont,
fill: 0x00aaff,
align: "center"
});
upg2x2.anchor.set(0.5, 0.5);
upg2x2.x = sx + colXOffset;
upg2x2.y = upgBtnY + upgBtnSpacingY;
upg2x2._isShipUpgradeBtn = true;
upg2x2._upgradeType = "maxShield";
upg2x2._upgradeCost = {
coins: 1440,
metal: 144,
energy: 0
};
upg2x2._isDoubleCost = true;
var upg3 = new Text2("Hasar +5\n(900 coin, 90 enerji)", {
size: upgBtnFont,
fill: 0xffcc00,
align: "center"
});
upg3.anchor.set(0.5, 0.5);
upg3.x = sx - colXOffset;
upg3.y = upgBtnY + upgBtnSpacingY * 2;
upg3._isShipUpgradeBtn = true;
upg3._upgradeType = "damage";
upg3._upgradeCost = {
coins: 900,
metal: 0,
energy: 90
};
var upg3x2 = new Text2("Hasar +5\n(1800 coin, 180 enerji)", {
size: upgBtnFont,
fill: 0xff9900,
align: "center"
});
upg3x2.anchor.set(0.5, 0.5);
upg3x2.x = sx + colXOffset;
upg3x2.y = upgBtnY + upgBtnSpacingY * 2;
upg3x2._isShipUpgradeBtn = true;
upg3x2._upgradeType = "damage";
upg3x2._upgradeCost = {
coins: 1800,
metal: 0,
energy: 180
};
upg3x2._isDoubleCost = true;
// Buy health button (if not full)
var canBuyHealth = ship.health < ship.maxHealth;
var buyHealthBtnFont = unifiedFontSize;
// Proportional cost scaling for buy health button
var healthToRestore = ship.maxHealth - ship.health;
var baseFullRepairHealth = 60;
var baseCoinCost = 90 * 2;
var baseMetalCost = 6 * 2;
var baseEnergyCost = 6 * 2;
var buyHealthCostCoins = Math.max(30, Math.round(baseCoinCost * (healthToRestore / baseFullRepairHealth)));
var buyHealthCostMetal = Math.max(2, Math.round(baseMetalCost * (healthToRestore / baseFullRepairHealth)));
var buyHealthCostEnergy = Math.max(2, Math.round(baseEnergyCost * (healthToRestore / baseFullRepairHealth)));
var buyHealthBtn = new Text2("Canı Doldur (" + buyHealthCostCoins + " coin, " + buyHealthCostMetal + " metal, " + buyHealthCostEnergy + " enerji)", {
size: buyHealthBtnFont,
fill: canBuyHealth ? 0x00ffcc : 0x888888,
align: "center"
});
buyHealthBtn.anchor.set(0.5, 0.5);
buyHealthBtn.x = sx;
buyHealthBtn.y = upgBtnY + upgBtnSpacingY * 3 + 30;
buyHealthBtn._isShipBuyHealthBtn = true;
buyHealthBtn._repairCostCoins = buyHealthCostCoins;
buyHealthBtn._repairCostMetal = buyHealthCostMetal;
buyHealthBtn._repairCostEnergy = buyHealthCostEnergy;
// Speed upgrade button (bottom of panel)
var speedUpgLevel = window.shipSpeedUpgradeLevel || 0;
var speedUpgFont = unifiedFontSize;
var speedUpgCost = Math.round((120 + speedUpgLevel * 60) * 1.9);
var speedUpgBtn = new Text2("Hız +" + Math.round((speedUpgLevel + 1) * 10) + "%\n(" + speedUpgCost + " coin)", {
size: speedUpgFont,
fill: 0x00ffff,
align: "center"
});
speedUpgBtn.anchor.set(0.5, 0.5);
speedUpgBtn.x = sx;
speedUpgBtn.y = buyHealthBtn.y + upgBtnSpacingY;
speedUpgBtn._isShipSpeedUpgradeBtn = true;
speedUpgBtn._speedUpgradeLevel = speedUpgLevel;
speedUpgBtn._speedUpgradeCost = speedUpgCost;
// Close button
var closeBtn = new Text2("Kapat", {
size: unifiedFontSize + 4,
// 2 font larger than Coins
fill: 0xff4444,
align: "center"
});
closeBtn.anchor.set(0.5, 0.5);
// Move close button above the panel title, with extra margin
closeBtn.x = sx;
closeBtn.y = title.y - 110; // further above title
closeBtn._isShipUpgradeCloseBtn = true;
// Add to game
game.addChild(panel);
game.addChild(title);
game.addChild(upg1);
game.addChild(upg1x2);
game.addChild(upg2);
game.addChild(upg2x2);
game.addChild(upg3);
game.addChild(upg3x2);
game.addChild(buyHealthBtn);
game.addChild(speedUpgBtn);
game.addChild(closeBtn);
// Store refs for tap logic/cleanup
window.shipUpgradePanel = panel;
window.shipUpgradeTitle = title;
window.shipUpgradeBtn1 = upg1;
window.shipUpgradeBtn1x2 = upg1x2;
window.shipUpgradeBtn2 = upg2;
window.shipUpgradeBtn2x2 = upg2x2;
window.shipUpgradeBtn3 = upg3;
window.shipUpgradeBtn3x2 = upg3x2;
window.shipBuyHealthBtn = buyHealthBtn;
window.shipSpeedUpgradeBtn = speedUpgBtn;
window.shipUpgradeCloseBtn = closeBtn;
}
return;
}
}
if (Math.sqrt(Math.pow(x - joystickBase.x, 2) + Math.pow(y - joystickBase.y, 2)) < 100) {
isDragging = true;
joystickHandle.x = x;
joystickHandle.y = y;
} else {
// --- SHIP UPGRADE PANEL BUTTONS ---
if (window.shipUpgradePanel) {
// Upgrade buttons
var btns = [window.shipUpgradeBtn1, window.shipUpgradeBtn1x2, window.shipUpgradeBtn2, window.shipUpgradeBtn2x2, window.shipUpgradeBtn3, window.shipUpgradeBtn3x2];
for (var i = 0; i < btns.length; i++) {
var btn = btns[i];
if (!btn) continue;
var bx = btn.x,
by = btn.y;
if (x > bx - 120 && x < bx + 120 && y > by - 50 && y < by + 50) {
// Try to buy upgrade
var upg = btn._upgradeType;
var cost = btn._upgradeCost;
var isDouble = !!btn._isDoubleCost;
if (upg === "maxHealth" && playerCoins >= cost.coins && playerMetal >= cost.metal) {
ship.maxHealth += 20;
ship.health = ship.maxHealth;
playerCoins -= cost.coins;
playerMetal -= cost.metal;
LK.effects.flashObject(ship, isDouble ? 0x00cc99 : 0x00ff99, 400);
btn.setText("Alındı!");
btn.fill = 0x00ffcc;
updateUI();
saveProgress();
} else if (upg === "maxShield" && playerCoins >= cost.coins && playerMetal >= cost.metal) {
ship.maxShield += 10;
ship.shield = ship.maxShield;
playerCoins -= cost.coins;
playerMetal -= cost.metal;
LK.effects.flashObject(ship, isDouble ? 0x00aaff : 0x00ccff, 400);
btn.setText("Alındı!");
btn.fill = 0x00ffcc;
updateUI();
saveProgress();
} else if (upg === "damage" && playerCoins >= cost.coins && playerEnergy >= cost.energy) {
ship.damage += 5;
playerCoins -= cost.coins;
playerEnergy -= cost.energy;
LK.effects.flashObject(ship, isDouble ? 0xff9900 : 0xffcc00, 400);
btn.setText("Alındı!");
btn.fill = 0x00ffcc;
updateUI();
saveProgress();
} else {
btn.setText("Yetersiz kaynak!");
btn.fill = 0xff4444;
}
return;
}
}
// Buy health button
var bhb = window.shipBuyHealthBtn;
if (bhb) {
var bx = bhb.x,
by = bhb.y;
if (x > bx - 180 && x < bx + 180 && y > by - 50 && y < by + 50) {
if (ship.health < ship.maxHealth) {
var costCoins = bhb._repairCostCoins,
costMetal = bhb._repairCostMetal,
costEnergy = bhb._repairCostEnergy;
if (playerCoins >= costCoins && playerMetal >= costMetal && playerEnergy >= costEnergy) {
playerCoins -= costCoins;
playerMetal -= costMetal;
playerEnergy -= costEnergy;
ship.health = ship.maxHealth;
updateUI();
saveProgress();
bhb.setText("Can Dolduruldu!");
bhb.fill = 0x00ffcc;
} else {
bhb.setText("Yetersiz kaynak!");
bhb.fill = 0xff4444;
}
} else {
bhb.setText("Can zaten tam!");
bhb.fill = 0x888888;
}
return;
}
}
// Speed upgrade button
var sub = window.shipSpeedUpgradeBtn;
if (sub) {
var bx = sub.x,
by = sub.y;
if (x > bx - 180 && x < bx + 180 && y > by - 50 && y < by + 50) {
var level = window.shipSpeedUpgradeLevel || 0;
var cost = Math.round((120 + level * 60) * 1.9);
if (playerCoins >= cost) {
playerCoins -= cost;
level++;
window.shipSpeedUpgradeLevel = level;
// Each level increases speed by 10% (multiplicative)
ship.speed = Math.round(ship.speed * Math.pow(1.1, 1) * 100) / 100;
sub.setText("Alındı! +" + level * 10 + "%");
sub.fill = 0x00ffcc;
LK.effects.flashObject(ship, 0x00ffff, 400);
updateUI();
saveProgress();
} else {
sub.setText("Yetersiz coin!");
sub.fill = 0xff4444;
}
return;
}
}
// Close button
var cb = window.shipUpgradeCloseBtn;
if (cb) {
var bx = cb.x,
by = cb.y;
if (x > bx - 120 && x < bx + 120 && y > by - 50 && y < by + 50) {
// Remove all panel elements
if (window.shipUpgradePanel && window.shipUpgradePanel.parent) window.shipUpgradePanel.parent.removeChild(window.shipUpgradePanel);
if (window.shipUpgradeTitle && window.shipUpgradeTitle.parent) window.shipUpgradeTitle.parent.removeChild(window.shipUpgradeTitle);
if (window.shipUpgradeBtn1 && window.shipUpgradeBtn1.parent) window.shipUpgradeBtn1.parent.removeChild(window.shipUpgradeBtn1);
if (window.shipUpgradeBtn1x2 && window.shipUpgradeBtn1x2.parent) window.shipUpgradeBtn1x2.parent.removeChild(window.shipUpgradeBtn1x2);
if (window.shipUpgradeBtn2 && window.shipUpgradeBtn2.parent) window.shipUpgradeBtn2.parent.removeChild(window.shipUpgradeBtn2);
if (window.shipUpgradeBtn2x2 && window.shipUpgradeBtn2x2.parent) window.shipUpgradeBtn2x2.parent.removeChild(window.shipUpgradeBtn2x2);
if (window.shipUpgradeBtn3 && window.shipUpgradeBtn3.parent) window.shipUpgradeBtn3.parent.removeChild(window.shipUpgradeBtn3);
if (window.shipUpgradeBtn3x2 && window.shipUpgradeBtn3x2.parent) window.shipUpgradeBtn3x2.parent.removeChild(window.shipUpgradeBtn3x2);
if (window.shipBuyHealthBtn && window.shipBuyHealthBtn.parent) window.shipBuyHealthBtn.parent.removeChild(window.shipBuyHealthBtn);
if (window.shipSpeedUpgradeBtn && window.shipSpeedUpgradeBtn.parent) window.shipSpeedUpgradeBtn.parent.removeChild(window.shipSpeedUpgradeBtn);
if (window.shipUpgradeCloseBtn && window.shipUpgradeCloseBtn.parent) window.shipUpgradeCloseBtn.parent.removeChild(window.shipUpgradeCloseBtn);
// Hide all upgrade panel texts
window.shipUpgradePanel = null;
window.shipUpgradeTitle = null;
window.shipUpgradeBtn1 = null;
window.shipUpgradeBtn1x2 = null;
window.shipUpgradeBtn2 = null;
window.shipUpgradeBtn2x2 = null;
window.shipUpgradeBtn3 = null;
window.shipUpgradeBtn3x2 = null;
window.shipBuyHealthBtn = null;
window.shipSpeedUpgradeBtn = null;
window.shipUpgradeCloseBtn = null;
return;
}
}
}
// --- Handle Accept/Reject quest button taps ---
if (game._questDecisionAcceptBtn && game._questDecisionAcceptBtn.parent) {
var btn = game._questDecisionAcceptBtn;
var bx = btn.x,
by = btn.y;
// Button is about 180x80 px
if (x > bx - 90 && x < bx + 90 && y > by - 40 && y < by + 40) {
// Accept quest
var npc = btn._questNPC;
if (npc) {
// Defend quest özel: yardım kabul edildi
if (npc.questType === 'defend') {
npc._defendHelpAccepted = true;
// Show floating label for accepted
var acceptLabel = new Text2("Yardım kabul edildi!", {
size: 36,
fill: 0x00ff99,
align: "center"
});
acceptLabel.anchor.set(0.5, 0.5);
acceptLabel.x = npc.x;
acceptLabel.y = npc.y + 110;
game.addChild(acceptLabel);
npc._npcInteractionLabel = acceptLabel;
npc._npcInteractionLabelExpire = LK.ticks + 120;
npc.pauseUntil = LK.ticks + 120;
npc._npcText && npc._npcText.parent && npc._npcText.parent.removeChild(npc._npcText);
npc._npcText = new Text2(npc.rpgName + ": Teşekkürler! Beni korsanlardan koru!", {
size: 32,
fill: 0x00ffcc,
align: "center"
});
npc._npcText.anchor.set(0.5, 1);
npc._npcText.x = npc.x;
npc._npcText.y = npc.y - 70;
game.addChild(npc._npcText);
} else {
// Mark quest as accepted (progress 1 means started)
npc.questProgress = 1;
// Show NPC response
var acceptLabel = new Text2("Görev kabul edildi!", {
size: 36,
fill: 0x00ff99,
align: "center"
});
acceptLabel.anchor.set(0.5, 0.5);
acceptLabel.x = npc.x;
acceptLabel.y = npc.y + 110;
game.addChild(acceptLabel);
npc._npcInteractionLabel = acceptLabel;
npc._npcInteractionLabelExpire = LK.ticks + 120;
npc.pauseUntil = LK.ticks + 120;
npc._npcText && npc._npcText.parent && npc._npcText.parent.removeChild(npc._npcText);
npc._npcText = new Text2(npc.rpgName + ": Harika! Görev başladı.", {
size: 32,
fill: 0x00ffcc,
align: "center"
});
npc._npcText.anchor.set(0.5, 1);
npc._npcText.x = npc.x;
npc._npcText.y = npc.y - 70;
game.addChild(npc._npcText);
}
// Remove quest panel
if (npc._questDecisionPanel && npc._questDecisionPanel.parent) npc._questDecisionPanel.parent.removeChild(npc._questDecisionPanel);
if (npc._questDecisionText && npc._questDecisionText.parent) npc._questDecisionText.parent.removeChild(npc._questDecisionText);
if (npc._questDecisionAcceptBtn && npc._questDecisionAcceptBtn.parent) npc._questDecisionAcceptBtn.parent.removeChild(npc._questDecisionAcceptBtn);
if (npc._questDecisionRejectBtn && npc._questDecisionRejectBtn.parent) npc._questDecisionRejectBtn.parent.removeChild(npc._questDecisionRejectBtn);
npc._questDecisionPanel = null;
npc._questDecisionText = null;
npc._questDecisionAcceptBtn = null;
npc._questDecisionRejectBtn = null;
game._questDecisionPanel = null;
game._questDecisionAcceptBtn = null;
game._questDecisionRejectBtn = null;
game._questDecisionText = null;
game._questDecisionNPC = null;
}
return;
}
}
if (game._questDecisionRejectBtn && game._questDecisionRejectBtn.parent) {
var btn = game._questDecisionRejectBtn;
var bx = btn.x,
by = btn.y;
if (x > bx - 90 && x < bx + 90 && y > by - 40 && y < by + 40) {
// Reject quest
var npc = btn._questNPC;
if (npc) {
if (npc.questType === 'defend') {
npc._defendHelpAccepted = false;
// Show floating label for rejected
var rejectLabel = new Text2("Yardım edilmedi.", {
size: 36,
fill: 0xff4444,
align: "center"
});
rejectLabel.anchor.set(0.5, 0.5);
rejectLabel.x = npc.x;
rejectLabel.y = npc.y + 110;
game.addChild(rejectLabel);
npc._npcInteractionLabel = rejectLabel;
npc._npcInteractionLabelExpire = LK.ticks + 120;
npc.pauseUntil = LK.ticks + 120;
npc._npcText && npc._npcText.parent && npc._npcText.parent.removeChild(npc._npcText);
npc._npcText = new Text2(npc.rpgName + ": Anlaşıldı, kendi başıma savaşacağım!", {
size: 32,
fill: 0x00ffcc,
align: "center"
});
npc._npcText.anchor.set(0.5, 1);
npc._npcText.x = npc.x;
npc._npcText.y = npc.y - 70;
game.addChild(npc._npcText);
} else {
// Mark quest as inactive
npc.questActive = false;
// Show floating label for rejected
var rejectLabel = new Text2("Görev reddedildi.", {
size: 36,
fill: 0xff4444,
align: "center"
});
rejectLabel.anchor.set(0.5, 0.5);
rejectLabel.x = npc.x;
rejectLabel.y = npc.y + 110;
game.addChild(rejectLabel);
npc._npcInteractionLabel = rejectLabel;
npc._npcInteractionLabelExpire = LK.ticks + 120;
npc.pauseUntil = LK.ticks + 120;
npc._npcText && npc._npcText.parent && npc._npcText.parent.removeChild(npc._npcText);
npc._npcText = new Text2(npc.rpgName + ": Belki başka zaman!", {
size: 32,
fill: 0x00ffcc,
align: "center"
});
npc._npcText.anchor.set(0.5, 1);
npc._npcText.x = npc.x;
npc._npcText.y = npc.y - 70;
game.addChild(npc._npcText);
}
// Remove quest panel
if (npc._questDecisionPanel && npc._questDecisionPanel.parent) npc._questDecisionPanel.parent.removeChild(npc._questDecisionPanel);
if (npc._questDecisionText && npc._questDecisionText.parent) npc._questDecisionText.parent.removeChild(npc._questDecisionText);
if (npc._questDecisionAcceptBtn && npc._questDecisionAcceptBtn.parent) npc._questDecisionAcceptBtn.parent.removeChild(npc._questDecisionAcceptBtn);
if (npc._questDecisionRejectBtn && npc._questDecisionRejectBtn.parent) npc._questDecisionRejectBtn.parent.removeChild(npc._questDecisionRejectBtn);
npc._questDecisionPanel = null;
npc._questDecisionText = null;
npc._questDecisionAcceptBtn = null;
npc._questDecisionRejectBtn = null;
game._questDecisionPanel = null;
game._questDecisionAcceptBtn = null;
game._questDecisionRejectBtn = null;
game._questDecisionText = null;
game._questDecisionNPC = null;
}
return;
}
}
// Check for NPC tap (RPG/adventure/trade)
for (var i = 0; i < npcs.length; i++) {
var npc = npcs[i];
var dist = Math.sqrt(Math.pow(npc.x - ship.x, 2) + Math.pow(npc.y - ship.y, 2));
if (dist < 180) {
game._lastNPCTap = LK.ticks;
break;
}
}
// --- Distress event tap detection ---
if (window.distressEvent && window.distressEvent.helpBtn && window.distressEvent.ignoreBtn) {
game._lastDistressTapTick = LK.ticks;
game._lastDistressTapX = x;
game._lastDistressTapY = y;
}
}
};
game.move = function (x, y, obj) {
if (isDragging) {
var dx = x - joystickBase.x;
var dy = y - joystickBase.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 100) {
dx = dx / distance * 100;
dy = dy / distance * 100;
}
joystickHandle.x = joystickBase.x + dx;
joystickHandle.y = joystickBase.y + dy;
}
};
game.up = function (x, y, obj) {
isDragging = false;
joystickHandle.x = joystickBase.x;
joystickHandle.y = joystickBase.y;
};
// Main game loop
game.update = function () {
// Ship movement
var shipDX = 0;
var shipDY = 0;
if (isDragging) {
var dx = joystickHandle.x - joystickBase.x;
var dy = joystickHandle.y - joystickBase.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 10) {
var effectiveSpeed = ship.speed;
shipDX = dx / 100 * effectiveSpeed;
shipDY = dy / 100 * effectiveSpeed;
ship.rotation = Math.atan2(dy, dx) + Math.PI / 2;
}
}
ship.x += shipDX;
ship.y += shipDY;
// Track total distance traveled
totalDistance += Math.sqrt(shipDX * shipDX + shipDY * shipDY);
// Update camera to follow ship movement
camera.x += shipDX;
camera.y += shipDY;
// Move all world objects opposite to ship movement to create camera effect
for (var i = 0; i < stars.length; i++) {
stars[i].x -= shipDX;
stars[i].y -= shipDY;
}
for (var i = 0; i < npcs.length; i++) {
npcs[i].x -= shipDX;
npcs[i].y -= shipDY;
}
for (var i = 0; i < pirates.length; i++) {
pirates[i].x -= shipDX;
pirates[i].y -= shipDY;
}
for (var i = 0; i < coins.length; i++) {
coins[i].x -= shipDX;
coins[i].y -= shipDY;
}
for (var i = 0; i < resources.length; i++) {
resources[i].x -= shipDX;
resources[i].y -= shipDY;
}
for (var i = 0; i < bullets.length; i++) {
bullets[i].x -= shipDX;
bullets[i].y -= shipDY;
}
for (var i = 0; i < enemyBullets.length; i++) {
enemyBullets[i].x -= shipDX;
enemyBullets[i].y -= shipDY;
}
for (var i = 0; i < asteroids.length; i++) {
asteroids[i].x -= shipDX;
asteroids[i].y -= shipDY;
}
for (var i = 0; i < upgradeStations.length; i++) {
upgradeStations[i].x -= shipDX;
upgradeStations[i].y -= shipDY;
}
// boostParticles removed (no boost system)
for (var i = 0; i < explosions.length; i++) {
explosions[i].x -= shipDX;
explosions[i].y -= shipDY;
}
// Auto fire at very close pirates or asteroids
// Saldırı mesafesi %10 arttırıldı (200 -> 220)
var ATTACK_RANGE = 220;
if (LK.ticks - ship.lastFire > ship.fireRate && (pirates.length > 0 || asteroids.length > 0)) {
// Find nearest pirate or asteroid within 220 pixels
var nearestTarget = null;
var nearestDistance = Infinity;
var isPirate = false;
// Check pirates
for (var i = 0; i < pirates.length; i++) {
var dist = Math.sqrt(Math.pow(pirates[i].x - ship.x, 2) + Math.pow(pirates[i].y - ship.y, 2));
if (dist < ATTACK_RANGE && dist < nearestDistance) {
nearestDistance = dist;
nearestTarget = pirates[i];
isPirate = true;
}
}
// Check asteroids
for (var i = 0; i < asteroids.length; i++) {
var dist = Math.sqrt(Math.pow(asteroids[i].x - ship.x, 2) + Math.pow(asteroids[i].y - ship.y, 2));
if (dist < ATTACK_RANGE && dist < nearestDistance) {
nearestDistance = dist;
nearestTarget = asteroids[i];
isPirate = false;
}
}
if (nearestTarget) {
var bullet = new Bullet();
bullet.x = ship.x;
bullet.y = ship.y;
var angle = Math.atan2(nearestTarget.y - ship.y, nearestTarget.x - ship.x);
bullet.directionX = Math.cos(angle);
bullet.directionY = Math.sin(angle);
bullet.rotation = angle + Math.PI / 2;
bullets.push(bullet);
game.addChild(bullet);
ship.lastFire = LK.ticks;
LK.getSound('shoot').play();
}
}
// Update bullets
for (var i = bullets.length - 1; i >= 0; i--) {
var bullet = bullets[i];
if (bullet.x < -50 || bullet.x > 2098 || bullet.y < -50 || bullet.y > 2782) {
bullet.destroy();
bullets.splice(i, 1);
continue;
}
// Check collision with pirates
for (var j = pirates.length - 1; j >= 0; j--) {
if (bullet.intersects(pirates[j])) {
pirates[j].takeDamage(bullet.damage);
var killedByPlayer = !bullet._npcBullet;
var killedByNPC = !!bullet._npcBullet;
if (pirates[j].health <= 0) {
enemiesKilled++;
createExplosion(pirates[j].x, pirates[j].y);
// Drop loot
var coin = new Coin();
coin.x = pirates[j].x;
coin.y = pirates[j].y;
coin.value = coin.value * (1 + Math.floor(waveNumber / 3));
coins.push(coin);
game.addChild(coin);
if (Math.random() < 0.3) {
var resource = new Resource();
resource.x = pirates[j].x + (Math.random() - 0.5) * 50;
resource.y = pirates[j].y + (Math.random() - 0.5) * 50;
resources.push(resource);
game.addChild(resource);
}
// Remove KILL label after 2 seconds if present
if (pirates[j]._killLabel) {
// If not already expiring, set expire tick
if (!pirates[j]._killLabel._expireTick) {
pirates[j]._killLabel._expireTick = LK.ticks + 120;
}
}
// Remove KILL label if expired
if (pirates[j]._killLabel && pirates[j]._killLabel._expireTick && LK.ticks > pirates[j]._killLabel._expireTick) {
if (pirates[j]._killLabel.parent) pirates[j]._killLabel.parent.removeChild(pirates[j]._killLabel);
pirates[j]._killLabel = null;
}
if (killedByPlayer) {
// Oyuncu öldürdü: sadece exp kazan
var pirateExp = 3 + Math.floor(Math.random() * 3);
playerEXP += pirateExp;
// Level up if enough EXP
while (playerEXP >= expToNext(playerLevel)) {
playerEXP -= expToNext(playerLevel);
playerLevel++;
LK.effects.flashObject(ship, 0x00ffcc, 800);
}
} else if (killedByNPC) {
// NPC öldürdü: yoluna devam etsin, rep/exp yok
// Kısa bir etiket göster (isteğe bağlı)
var npcLabel = new Text2("NPC KILL", {
size: 28,
fill: 0xccccff,
align: "center"
});
npcLabel.anchor.set(0.5, 0.5);
npcLabel.x = pirates[j].x;
npcLabel.y = pirates[j].y - 80;
game.addChild(npcLabel);
// Fade out and remove after 700ms
LK.setTimeout(function () {
if (npcLabel.parent) {
npcLabel.parent.removeChild(npcLabel);
}
}, 700);
}
// Update UI after EXP gain
updateUI();
pirates[j].destroy();
pirates.splice(j, 1);
// Check for wave completion
if (enemiesKilled >= 10 + waveNumber * 5) {
waveNumber++;
enemiesKilled = 0;
// Spawn upgrade station every 3 waves
if (waveNumber % 3 === 0) {
spawnUpgradeStation();
}
}
}
bullet.destroy();
bullets.splice(i, 1);
LK.getSound('hit').play();
break;
}
}
// --- PLAYER CAN ATTACK NPCs IF FIGHT MODE IS ON ---
if (window.npcFightMode) {
for (var j = npcs.length - 1; j >= 0; j--) {
var npc = npcs[j];
if (bullet.intersects(npc)) {
if (typeof npc.health === "undefined") npc.health = 100;
npc.health -= bullet.damage;
LK.effects.flashObject(npc, 0xff0000, 120);
// Floating label for NPC hit
var npcHitLabel = new Text2("NPC HIT", {
size: 24,
fill: 0xff8888,
align: "center"
});
npcHitLabel.anchor.set(0.5, 0.5);
npcHitLabel.x = npc.x;
npcHitLabel.y = npc.y - 60;
game.addChild(npcHitLabel);
LK.setTimeout(function (label) {
if (label.parent) label.parent.removeChild(label);
}.bind(null, npcHitLabel), 600);
// Remove NPC if dead
if (npc.health <= 0) {
// Floating label for NPC kill
var npcKillLabel = new Text2("NPC KILL", {
size: 28,
fill: 0xccccff,
align: "center"
});
npcKillLabel.anchor.set(0.5, 0.5);
npcKillLabel.x = npc.x;
npcKillLabel.y = npc.y - 80;
game.addChild(npcKillLabel);
LK.setTimeout(function (label) {
if (label.parent) label.parent.removeChild(label);
}.bind(null, npcKillLabel), 700);
// Oyuncu NPC öldürdü: coin kaybı uygula
var coinLoss = 10 + Math.floor(Math.random() * 41); // 10-50 arası coin kaybı
playerCoins = Math.max(0, playerCoins - coinLoss);
// Kısa bir etiket göster
var coinLossLabel = new Text2("-" + coinLoss + " coin", {
size: 28,
fill: 0xff4444,
align: "center"
});
coinLossLabel.anchor.set(0.5, 0.5);
coinLossLabel.x = npc.x;
coinLossLabel.y = npc.y - 120;
game.addChild(coinLossLabel);
LK.setTimeout(function (label) {
if (label.parent) label.parent.removeChild(label);
}, 900, coinLossLabel);
updateUI();
// Remove hostile label if present
if (npc._hostileLabel && npc._hostileLabel.parent) {
npc._hostileLabel.parent.removeChild(npc._hostileLabel);
npc._hostileLabel = null;
}
// Instantly remove Düşman! label if it exists (defensive, in case above missed)
if (npc._hostileLabel && npc._hostileLabel.parent) {
npc._hostileLabel.parent.removeChild(npc._hostileLabel);
npc._hostileLabel = null;
}
npc.destroy();
npcs.splice(j, 1);
}
bullet.destroy();
bullets.splice(i, 1);
LK.getSound('hit').play();
break;
}
}
}
// Check collision with asteroids
for (var j = asteroids.length - 1; j >= 0; j--) {
if (bullet.intersects(asteroids[j])) {
asteroids[j].takeDamage(bullet.damage);
if (asteroids[j].health <= 0) {
// Drop multiple resources (reduced by 80%)
var dropCount = Math.max(1, Math.floor(asteroids[j].resources * 0.2));
for (var k = 0; k < dropCount; k++) {
var resource = new Resource();
resource.x = asteroids[j].x + (Math.random() - 0.5) * 100;
resource.y = asteroids[j].y + (Math.random() - 0.5) * 100;
resource.amount = Math.floor(Math.random() * 3) + 1;
resources.push(resource);
game.addChild(resource);
}
createExplosion(asteroids[j].x, asteroids[j].y);
asteroids[j].destroy();
asteroids.splice(j, 1);
}
bullet.destroy();
bullets.splice(i, 1);
LK.getSound('hit').play();
break;
}
}
}
// Update enemy bullets
for (var i = enemyBullets.length - 1; i >= 0; i--) {
var bullet = enemyBullets[i];
if (bullet.x < -50 || bullet.x > 2098 || bullet.y < -50 || bullet.y > 2782) {
bullet.destroy();
enemyBullets.splice(i, 1);
continue;
}
if (bullet.intersects(ship)) {
ship.takeDamage(bullet.damage);
updateUI();
bullet.destroy();
enemyBullets.splice(i, 1);
LK.getSound('hit').play();
continue;
}
// --- NEW: Pirate bullets can hit NPCs ---
for (var n = npcs.length - 1; n >= 0; n--) {
var npc = npcs[n];
if (bullet.intersects(npc)) {
// Damage NPC
if (typeof npc.health === "undefined") npc.health = 100;
npc.health -= bullet.damage;
LK.effects.flashObject(npc, 0xff0000, 120);
// Floating label for NPC hit (optional)
var npcHitLabel = new Text2("NPC HIT", {
size: 24,
fill: 0xff8888,
align: "center"
});
npcHitLabel.anchor.set(0.5, 0.5);
npcHitLabel.x = npc.x;
npcHitLabel.y = npc.y - 60;
game.addChild(npcHitLabel);
LK.setTimeout(function (label) {
if (label.parent) label.parent.removeChild(label);
}.bind(null, npcHitLabel), 600);
// Remove NPC if dead
if (npc.health <= 0) {
// Floating label for NPC kill
var npcKillLabel = new Text2("NPC KILL", {
size: 28,
fill: 0xccccff,
align: "center"
});
npcKillLabel.anchor.set(0.5, 0.5);
npcKillLabel.x = npc.x;
npcKillLabel.y = npc.y - 80;
game.addChild(npcKillLabel);
LK.setTimeout(function (label) {
if (label.parent) label.parent.removeChild(label);
}.bind(null, npcKillLabel), 700);
// Remove hostile label if present
if (npc._hostileLabel && npc._hostileLabel.parent) {
npc._hostileLabel.parent.removeChild(npc._hostileLabel);
npc._hostileLabel = null;
}
// Remove NPC from world
npc.destroy();
npcs.splice(n, 1);
}
bullet.destroy();
enemyBullets.splice(i, 1);
LK.getSound('hit').play();
break;
}
}
}
// Update pirates
for (var i = 0; i < pirates.length; i++) {
var pirate = pirates[i];
if (pirate._healthBar && pirate._healthBar.update) pirate._healthBar.update();
// --- Pirate AI: Always attack the nearest target (NPC or player) ---
var nearestTarget = null;
var minDist = Infinity;
// Find nearest NPC
for (var n = 0; n < npcs.length; n++) {
var npc = npcs[n];
var distToNPC = Math.sqrt(Math.pow(npc.x - pirate.x, 2) + Math.pow(npc.y - pirate.y, 2));
if (distToNPC < minDist) {
minDist = distToNPC;
nearestTarget = npc;
}
}
// Compare with player distance
var distToPlayer = Math.sqrt(Math.pow(ship.x - pirate.x, 2) + Math.pow(ship.y - pirate.y, 2));
if (distToPlayer < minDist) {
minDist = distToPlayer;
nearestTarget = ship;
}
// If there is a target, move and attack
if (nearestTarget && minDist < 600) {
// --- 5% mesafe kuralı: hedefe %5 mesafe bırak, iç içe girme ---
var targetRadius = 40; // Varsayılan hedef yarıçapı (NPC/ship/pirate boyutu)
if (nearestTarget._healthBar && nearestTarget._healthBar._width) {
targetRadius = Math.max(targetRadius, nearestTarget._healthBar._width / 2);
}
var selfRadius = 35; // Korsan yarıçapı
if (pirate._healthBar && pirate._healthBar._width) {
selfRadius = Math.max(selfRadius, pirate._healthBar._width / 2);
}
var minBuffer = (minDist + selfRadius + targetRadius) * 0.05; // %5 buffer
var minAllowedDist = selfRadius + targetRadius + minBuffer;
var angle = Math.atan2(nearestTarget.y - pirate.y, nearestTarget.x - pirate.x);
// Sadece minAllowedDist'ten uzaktaysa yaklaş
if (minDist > minAllowedDist) {
var moveDist = Math.min(pirate.speed, minDist - minAllowedDist);
pirate.x += Math.cos(angle) * moveDist;
pirate.y += Math.sin(angle) * moveDist;
pirate.rotation = angle + Math.PI / 2;
} else {
// Hedefe çok yaklaştıysa sadece dön, hareket etme
pirate.rotation = angle + Math.PI / 2;
}
// Shoot at target
if (LK.ticks - pirate.lastFire > pirate.fireRate) {
var bullet = new EnemyBullet();
bullet.x = pirate.x;
bullet.y = pirate.y;
bullet.directionX = Math.cos(angle);
bullet.directionY = Math.sin(angle);
bullet.rotation = angle + Math.PI / 2;
bullet._pirateBullet = true;
enemyBullets.push(bullet);
game.addChild(bullet);
pirate.lastFire = LK.ticks;
}
} else {
// Wander randomly
pirate.x += Math.cos(pirate.moveAngle) * pirate.speed * 0.5;
pirate.y += Math.sin(pirate.moveAngle) * pirate.speed * 0.5;
}
// Remove pirates that are too far away
var dist = Math.sqrt(Math.pow(ship.x - pirate.x, 2) + Math.pow(ship.y - pirate.y, 2));
if (dist > 2000) {
pirate.destroy();
pirates.splice(i, 1);
i--;
}
}
// Update NPCs
for (var i = npcs.length - 1; i >= 0; i--) {
var npc = npcs[i];
if (npc._healthBar && npc._healthBar.update) npc._healthBar.update();
// Remove NPCs that are too far away
var dist = Math.sqrt(Math.pow(npc.x - ship.x, 2) + Math.pow(npc.y - ship.y, 2));
if (dist > 2500) {
npc.destroy();
npcs.splice(i, 1);
continue;
}
// Remove any floating text if player is not close
if (npc._npcText && npc._npcText.parent) {
npc._npcText.parent.removeChild(npc._npcText);
npc._npcText = null;
}
// --- NPC ATTITUDE: Rep sistemi kaldırıldı, sadece NPC Saldırı butonuna göre saldırı ---
// Eğer NPC Saldırı aktifse, her durumda NPC'ler oyuncuya saldırır
var npcHostile = false;
if (window.npcSaldiriBtn && window.npcSaldiriBtn._active) {
npcHostile = true;
} else {
npcHostile = false;
}
// --- NPC AI: Always attack the nearest target (pirate or player) ---
// If NPC Saldırı is PASİF, NPCs never attack the player
var nearestTarget = null;
var minDist = Infinity;
// Find nearest pirate
for (var j = 0; j < pirates.length; j++) {
var p = pirates[j];
if (p._destroyed) continue;
var d = Math.sqrt(Math.pow(p.x - npc.x, 2) + Math.pow(p.y - npc.y, 2));
if (d < minDist) {
minDist = d;
nearestTarget = p;
}
}
// Compare with player distance only if NPC Saldırı is AKTİF
var npcSaldiriActive = window.npcSaldiriBtn && window.npcSaldiriBtn._active;
if (npcSaldiriActive) {
var distToPlayer = Math.sqrt(Math.pow(ship.x - npc.x, 2) + Math.pow(ship.y - npc.y, 2));
if (distToPlayer < minDist) {
minDist = distToPlayer;
nearestTarget = ship;
}
}
// If there is a target, move and attack
if (nearestTarget && minDist < 600) {
// --- 5% mesafe kuralı: hedefe %5 mesafe bırak, iç içe girme ---
var targetRadius = 40;
if (nearestTarget._healthBar && nearestTarget._healthBar._width) {
targetRadius = Math.max(targetRadius, nearestTarget._healthBar._width / 2);
}
var selfRadius = 30;
if (npc._healthBar && npc._healthBar._width) {
selfRadius = Math.max(selfRadius, npc._healthBar._width / 2);
}
var minBuffer = (minDist + selfRadius + targetRadius) * 0.05;
var minAllowedDist = selfRadius + targetRadius + minBuffer;
var dx = nearestTarget.x - npc.x;
var dy = nearestTarget.y - npc.y;
var d = Math.sqrt(dx * dx + dy * dy);
if (d > minAllowedDist) {
var moveDist = Math.min(npc.moveSpeed * 1.2, d - minAllowedDist);
npc.x += dx / d * moveDist;
npc.y += dy / d * moveDist;
}
// Shoot at target (use NPC bullet fire rate)
if (typeof npc._aiAttackTimer === "undefined") npc._aiAttackTimer = 0;
npc._aiAttackTimer++;
// Use the same fire rate as pirates (EnemyBullet speed)
var npcFireRate = 8;
if (typeof npc.fireRate === "number") {
npcFireRate = npc.fireRate;
} else {
npcFireRate = 40;
}
if (d < 300 && npc._aiAttackTimer > npcFireRate) {
var bullet;
var angle = Math.atan2(nearestTarget.y - npc.y, nearestTarget.x - npc.x);
if (nearestTarget === ship) {
bullet = new EnemyBullet();
bullet._npcBullet = true;
} else {
bullet = new Bullet();
bullet._npcBullet = true;
}
bullet.x = npc.x;
bullet.y = npc.y;
bullet.directionX = Math.cos(angle);
bullet.directionY = Math.sin(angle);
bullet.rotation = angle + Math.PI / 2;
if (nearestTarget === ship) {
enemyBullets.push(bullet);
} else {
bullets.push(bullet);
}
game.addChild(bullet);
npc._aiAttackTimer = 0;
}
// Show angry label above NPC if attacking player
if (nearestTarget === ship) {
if (!npc._hostileLabel || !npc._hostileLabel.parent) {
npc._hostileLabel = new Text2("Düşman!", {
size: 32,
fill: 0xff4444,
align: "center"
});
npc._hostileLabel.anchor.set(0.5, 0.5);
npc._hostileLabel.x = npc.x;
npc._hostileLabel.y = npc.y - 80;
npc._hostileLabel.alpha = 1;
game.addChild(npc._hostileLabel);
}
if (npc._hostileLabel) {
npc._hostileLabel.x = npc.x;
npc._hostileLabel.y = npc.y - 80;
npc._hostileLabel.alpha = 1;
npc._hostileLabel._expireTick = LK.ticks + 60; // 1 second
}
if (npc._hostileLabel && npc._hostileLabel._expireTick && LK.ticks > npc._hostileLabel._expireTick) {
if (npc._hostileLabel.parent) npc._hostileLabel.parent.removeChild(npc._hostileLabel);
npc._hostileLabel = null;
} else if (npc._hostileLabel && npc._hostileLabel._expireTick) {
var fadeStart = npc._hostileLabel._expireTick - 20;
if (LK.ticks > fadeStart) {
npc._hostileLabel.alpha = Math.max(0, (npc._hostileLabel._expireTick - LK.ticks) / 20);
} else {
npc._hostileLabel.alpha = 1;
}
}
} else {
// Remove hostile label if present
if (npc._hostileLabel && npc._hostileLabel.parent) {
npc._hostileLabel.parent.removeChild(npc._hostileLabel);
npc._hostileLabel = null;
}
}
} else {
// Remove hostile label if present
if (npc._hostileLabel && npc._hostileLabel.parent) {
npc._hostileLabel.parent.removeChild(npc._hostileLabel);
npc._hostileLabel = null;
}
}
}
// Update asteroids
for (var i = asteroids.length - 1; i >= 0; i--) {
var asteroid = asteroids[i];
if (asteroid._healthBar && asteroid._healthBar.update) asteroid._healthBar.update();
var dist = Math.sqrt(Math.pow(asteroid.x - ship.x, 2) + Math.pow(asteroid.y - ship.y, 2));
if (dist > 2500) {
asteroid.destroy();
asteroids.splice(i, 1);
}
}
// Update explosion particles
for (var i = explosions.length - 1; i >= 0; i--) {
var particle = explosions[i];
particle.x += particle.vx;
particle.y += particle.vy;
particle.vx *= 0.9;
particle.vy *= 0.9;
particle.life--;
particle.alpha = particle.life / 30;
particle.scaleX = particle.scaleY = 1 + (30 - particle.life) / 10;
if (particle.life <= 0) {
particle.destroy();
explosions.splice(i, 1);
}
}
// Collect items
for (var i = coins.length - 1; i >= 0; i--) {
if (coins[i].intersects(ship)) {
playerCoins += coins[i].value;
coins[i].destroy();
coins.splice(i, 1);
LK.getSound('collect').play();
updateUI();
saveProgress();
}
}
for (var i = resources.length - 1; i >= 0; i--) {
if (resources[i].intersects(ship)) {
// 10 tip için index bul
var resourceTypes = ['metal', 'energy', 'crystal', 'gas', 'ice', 'uranium', 'silicon', 'carbon', 'plasma', 'antimatter'];
var idx = resourceTypes.indexOf(resources[i].type);
if (idx >= 0) {
playerResources[idx] += resources[i].amount;
}
resources[i].destroy();
resources.splice(i, 1);
LK.getSound('collect').play();
updateUI();
saveProgress();
}
}
// Update stars
for (var i = stars.length - 1; i >= 0; i--) {
var dist = Math.sqrt(Math.pow(stars[i].x - ship.x, 2) + Math.pow(stars[i].y - ship.y, 2));
if (dist > 2000) {
stars[i].destroy();
stars.splice(i, 1);
}
}
// Spawn entities (star spawn frequency is now random interval)
if (typeof window._nextStarSpawnTick === "undefined") {
window._nextStarSpawnTick = LK.ticks + Math.floor(20 + Math.random() * 60); // 20-80 ticks
}
if (LK.ticks >= window._nextStarSpawnTick) {
spawnStar(true);
window._nextStarSpawnTick = LK.ticks + Math.floor(20 + Math.random() * 60); // 20-80 ticks
}
// Spawn pirates and NPCs at intervals
if (pirates.length < 6 && Math.random() < 0.3) {
spawnPirate();
}
if (npcs.length < 4 && Math.random() < 0.2) {
spawnNPC();
}
// Spawn Suçlu at rare intervals (max 2 at a time)
if (suclus.length < 2 && Math.random() < 0.04) {
var suclu = new Suclu();
// Spawn from edges of visible area
var edge = Math.floor(Math.random() * 4);
switch (edge) {
case 0:
// Top
suclu.x = ship.x + (Math.random() - 0.5) * 2000;
suclu.y = ship.y - 1700;
break;
case 1:
// Right
suclu.x = ship.x + 1700;
suclu.y = ship.y + (Math.random() - 0.5) * 2000;
break;
case 2:
// Bottom
suclu.x = ship.x + (Math.random() - 0.5) * 2000;
suclu.y = ship.y + 1700;
break;
case 3:
// Left
suclu.x = ship.x - 1700;
suclu.y = ship.y + (Math.random() - 0.5) * 2000;
break;
}
suclus.push(suclu);
game.addChild(suclu);
}
// --- ASTEROID SYSTEM RESTORED ---
// Spawn asteroids if less than 6 in the world (20% reduction from 8)
if (asteroids.length < 6 && Math.random() < 0.025) {
spawnAsteroid();
}
// Update score
LK.setScore(playerCoins + questsCompleted * 100 + enemiesKilled * 10 + Math.floor(totalDistance / 100));
if (ship._healthBar && ship._healthBar.update) ship._healthBar.update();
updateUI();
// --- AUTO-REPAIR PANEL WHEN HEALTH IS LOW OR HEALTH BAR TAPPED ---
// Show repair panel if health < 100% and not dead, and not already shown
if (!window.repairPanel && ship.health < ship.maxHealth && ship.health > 0 && window._showRepairPanel && (!window._repairPanelSuppressUntil || LK.ticks > window._repairPanelSuppressUntil)) {
// Calculate how much health will be restored
var healthToRestore = ship.maxHealth - ship.health;
// Proportional cost scaling
// Base costs for full repair: 90 coins, 6 metal, 6 energy (for 60 health missing)
// Scale linearly with health to restore, but clamp minimums
var baseFullRepairHealth = 60;
var baseCoinCost = 90 * 2;
var baseMetalCost = 6 * 2;
var baseEnergyCost = 6 * 2;
var repairCostCoins = Math.max(30, Math.round(baseCoinCost * (healthToRestore / baseFullRepairHealth)));
var repairCostMetal = Math.max(2, Math.round(baseMetalCost * (healthToRestore / baseFullRepairHealth)));
var repairCostEnergy = Math.max(2, Math.round(baseEnergyCost * (healthToRestore / baseFullRepairHealth)));
// Panel background
// --- DYNAMIC REPAIR PANEL SIZE BASED ON TEXT ---
var repairTextStr = "Gemi hasarlı! Tamir: " + repairCostCoins + " coin, " + repairCostMetal + " metal, " + repairCostEnergy + " enerji";
var repairPanelFontSize = 38;
var repairPanelWidth = Math.max(700, repairTextStr.length * repairPanelFontSize * 0.32);
var repairPanelHeight = 180 + repairPanelFontSize * 1.5; // text + buttons
var panel = LK.getAsset('resource', {
anchorX: 0.5,
anchorY: 0.5,
x: ship.x,
y: ship.y - 220,
scaleX: repairPanelWidth / 40,
scaleY: repairPanelHeight / 40,
tint: 0x224444
});
// Repair text
var repairText = new Text2("Gemi hasarlı! Tamir: " + repairCostCoins + " coin, " + repairCostMetal + " metal, " + repairCostEnergy + " enerji", {
size: 38,
fill: 0xffffff,
align: "center"
});
repairText.anchor.set(0.5, 0.5);
repairText.x = ship.x;
repairText.y = ship.y - 240;
// Repair button
var repairBtn = new Text2("Tamir Et", {
size: 44,
fill: 0x00ff99,
align: "center"
});
repairBtn.anchor.set(0.5, 0.5);
repairBtn.x = ship.x - 100;
repairBtn.y = ship.y - 160;
// Cancel button
var cancelBtn = new Text2("Kapat", {
size: 44,
fill: 0xff4444,
align: "center"
});
cancelBtn.anchor.set(0.5, 0.5);
cancelBtn.x = ship.x + 100;
cancelBtn.y = ship.y - 160;
// Add to game
game.addChild(panel);
game.addChild(repairText);
game.addChild(repairBtn);
game.addChild(cancelBtn);
// Store references for tap logic and cleanup
window.repairPanel = panel;
window.repairText = repairText;
window.repairBtn = repairBtn;
window.cancelRepairBtn = cancelBtn;
repairBtn._isRepairBtn = true;
cancelBtn._isCancelRepairBtn = true;
repairBtn._repairCostCoins = repairCostCoins;
repairBtn._repairCostMetal = repairCostMetal;
repairBtn._repairCostEnergy = repairCostEnergy;
window._showRepairPanel = false; // Reset flag
window._repairPanelSuppressUntil = null; // Reset suppression when panel is shown
} else if (window.repairPanel && ship.health >= ship.maxHealth * 0.7) {
// Remove repair panel if health is restored
if (window.repairPanel.parent) window.repairPanel.parent.removeChild(window.repairPanel);
if (window.repairText && window.repairText.parent) window.repairText.parent.removeChild(window.repairText);
if (window.repairBtn && window.repairBtn.parent) window.repairBtn.parent.removeChild(window.repairBtn);
if (window.cancelRepairBtn && window.cancelRepairBtn.parent) window.cancelRepairBtn.parent.removeChild(window.cancelRepairBtn);
window.repairPanel = null;
window.repairText = null;
window.repairBtn = null;
window.cancelRepairBtn = null;
window._showRepairPanel = false;
}
// If health < 50% and not dead, auto-show repair panel (legacy behavior)
if (!window.repairPanel && ship.health < ship.maxHealth * 0.5 && ship.health > 0) {
window._showRepairPanel = true;
}
// --- GAME TIME UPDATE ---
// Calculate elapsed time in seconds
var elapsedTicks = LK.ticks - gameStartTick;
var elapsedSeconds = Math.floor(elapsedTicks / 60);
var minutes = Math.floor(elapsedSeconds / 60);
var seconds = elapsedSeconds % 60;
if (typeof gameTimeText !== "undefined") {
// Format as mm:ss
var timeStr = "Game Time: " + minutes + ":" + (seconds < 10 ? "0" : "") + seconds;
gameTimeText.setText(timeStr);
// Always keep gameTimeText to the right of coinText
gameTimeText.x = coinText.x + coinText.width + 40;
gameTimeText.y = coinText.y;
}
// --- Synchronize LK.ticks with real game time ---
// This ensures all time-based systems use real elapsed time, not just frame count
LK.ticks = gameStartTick + Math.floor((Date.now() - (window._gameStartRealTime || (window._gameStartRealTime = Date.now()))) / (1000 / 60));
// Update coordinateText with current ship coordinates (rounded) in real time to the left of waveText
if (typeof coordinateText !== "undefined" && ship && typeof waveText !== "undefined") {
// Show the actual current coordinates of the ship
coordinateText.setText('X: ' + Math.round(ship.x) + ' Y: ' + Math.round(ship.y));
// Always keep coordinateText to the left of waveText, and keep size 30% smaller than expText
coordinateText.size = Math.round(expText.size * 0.7);
coordinateText.x = waveText.x - waveText.width - 30;
coordinateText.y = waveText.y + waveText.height / 2;
}
// --- QUEST TARGET ARROW INDICATOR ---
// Only one arrow at a time, create if needed
if (!window.questArrow) {
// Use a yellow triangle as arrow
var arrow = LK.getAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.5,
scaleY: 1.2,
tint: 0xffff00,
alpha: 0.85
});
arrow.visible = false;
window.questArrow = arrow;
game.addChild(arrow);
}
var showArrow = false;
var arrowX = 0,
arrowY = 0,
arrowRot = 0;
var questTarget = null;
var minDist = Infinity;
// Find the nearest active coordinate-based quest target
for (var i = 0; i < npcs.length; i++) {
var npc = npcs[i];
if (!npc.questActive || !npc.questTarget) continue;
// Only for coordinate-based quests
if (npc.questType === 'explore' || npc.questType === 'delivery' || npc.questType === 'escort' || npc.questType === 'hunt') {
// For hunt, questTarget can be a pirate, otherwise it's {x, y}
var tx, ty;
if (npc.questType === 'hunt' && npc.questTarget && npc.questTarget.x !== undefined && npc.questTarget.y !== undefined && !npc.questTarget._destroyed) {
tx = npc.questTarget.x;
ty = npc.questTarget.y;
} else if (npc.questTarget.x !== undefined && npc.questTarget.y !== undefined) {
tx = npc.questTarget.x;
ty = npc.questTarget.y;
}
if (typeof tx === "number" && typeof ty === "number") {
var dist = Math.sqrt(Math.pow(tx - ship.x, 2) + Math.pow(ty - ship.y, 2));
if (dist > 120 && dist < minDist) {
// Only show if not already at target
minDist = dist;
questTarget = {
x: tx,
y: ty
};
}
}
}
}
// --- Derelict ship arrow logic ---
if (!questTarget && window.derelictShip && window.derelictShip.x !== undefined && window.derelictShip.y !== undefined) {
var d = window.derelictShip;
var dist = Math.sqrt(Math.pow(d.x - ship.x, 2) + Math.pow(d.y - ship.y, 2));
if (dist > 120 && dist < 3000) {
questTarget = {
x: d.x,
y: d.y
};
}
}
if (questTarget) {
// Project questTarget to screen edge
var dx = questTarget.x - ship.x;
var dy = questTarget.y - ship.y;
var angle = Math.atan2(dy, dx);
// Screen center in game coordinates
var screenW = 2048,
screenH = 2732;
var margin = 90; // keep arrow inside screen
var cx = screenW / 2,
cy = screenH / 2;
// Find intersection with screen edge
var ex = cx + Math.cos(angle) * (Math.min(cx, cy) - margin);
var ey = cy + Math.sin(angle) * (Math.min(cx, cy) - margin);
// Clamp to screen bounds
ex = Math.max(margin, Math.min(screenW - margin, ex));
ey = Math.max(margin, Math.min(screenH - margin, ey));
// Don't show if target is on screen (within 40% of screen from center)
if (Math.abs(dx) > screenW * 0.2 || Math.abs(dy) > screenH * 0.2) {
showArrow = true;
arrowX = ex;
arrowY = ey;
arrowRot = angle + Math.PI / 2;
}
}
if (window.questArrow) {
window.questArrow.visible = showArrow;
if (showArrow) {
window.questArrow.x = arrowX;
window.questArrow.y = arrowY;
window.questArrow.rotation = arrowRot;
window.questArrow.alpha = 0.85 + Math.sin(LK.ticks * 0.1) * 0.15;
window.questArrow.scaleX = 2.5 + Math.sin(LK.ticks * 0.07) * 0.2;
window.questArrow.scaleY = 1.2 + Math.cos(LK.ticks * 0.09) * 0.1;
window.questArrow.zIndex = 9999;
}
}
// --- Remaining Distance Label for Quest/Event Target ---
// Only one label at a time, create if needed
if (!window.questDistanceLabel) {
var questDistanceLabel = new Text2('', {
size: Math.round(unifiedFontSize * 0.9),
fill: 0xffffff,
align: "center"
});
questDistanceLabel.anchor.set(0.5, 0.5);
questDistanceLabel.visible = false;
window.questDistanceLabel = questDistanceLabel;
game.addChild(questDistanceLabel);
}
var showDistanceLabel = false;
var labelX = 0,
labelY = 0,
labelText = '';
if (questTarget) {
// Calculate distance
var distToTarget = Math.sqrt(Math.pow(questTarget.x - ship.x, 2) + Math.pow(questTarget.y - ship.y, 2));
// Only show if not already at target and not on screen
if (showArrow && distToTarget > 120) {
showDistanceLabel = true;
// Place label near the arrow, but offset further outwards
var labelOffset = 70;
labelX = arrowX + Math.cos(arrowRot - Math.PI / 2) * labelOffset;
labelY = arrowY + Math.sin(arrowRot - Math.PI / 2) * labelOffset;
// Show in km if >1000, else in px
if (distToTarget >= 1000) {
labelText = Math.round(distToTarget / 10) / 100 + "k px";
} else {
labelText = Math.round(distToTarget) + " px";
}
// If quest is from an NPC, show a short label
for (var i = 0; i < npcs.length; i++) {
var npc = npcs[i];
if (npc.questActive && npc.questTarget && (npc.questType === 'explore' || npc.questType === 'delivery' || npc.questType === 'escort') && npc.questTarget.x === questTarget.x && npc.questTarget.y === questTarget.y) {
if (npc.questType === 'explore') labelText = "Keşif: " + labelText;else if (npc.questType === 'delivery') labelText = "Teslimat: " + labelText;else if (npc.questType === 'escort') labelText = "Eşlik: " + labelText;
break;
}
if (npc.questActive && npc.questType === 'hunt' && npc.questTarget && npc.questTarget.x === questTarget.x && npc.questTarget.y === questTarget.y) {
labelText = "Av: " + labelText;
break;
}
}
}
}
// Derelict ship distance
if (!showDistanceLabel && window.derelictShip && window.derelictShip.x !== undefined && window.derelictShip.y !== undefined) {
var d = window.derelictShip;
var dist = Math.sqrt(Math.pow(d.x - ship.x, 2) + Math.pow(d.y - ship.y, 2));
if (dist > 120 && dist < 3000 && window.questArrow && window.questArrow.visible) {
showDistanceLabel = true;
var labelOffset = 70;
labelX = window.questArrow.x + Math.cos(window.questArrow.rotation - Math.PI / 2) * labelOffset;
labelY = window.questArrow.y + Math.sin(window.questArrow.rotation - Math.PI / 2) * labelOffset;
labelText = "Gemi: " + (dist >= 1000 ? Math.round(dist / 10) / 100 + "k px" : Math.round(dist) + " px");
}
}
// Distress event distance
if (!showDistanceLabel && window.distressEvent && window.distressEvent.x !== undefined && window.distressEvent.y !== undefined) {
var e = window.distressEvent;
var dist = Math.sqrt(Math.pow(e.x - ship.x, 2) + Math.pow(e.y - ship.y, 2));
if (dist > 120 && dist < 3000 && window.questArrow && window.questArrow.visible) {
showDistanceLabel = true;
var labelOffset = 70;
labelX = window.questArrow.x + Math.cos(window.questArrow.rotation - Math.PI / 2) * labelOffset;
labelY = window.questArrow.y + Math.sin(window.questArrow.rotation - Math.PI / 2) * labelOffset;
labelText = "İmdat: " + (dist >= 1000 ? Math.round(dist / 10) / 100 + "k px" : Math.round(dist) + " px");
}
}
if (window.questDistanceLabel) {
window.questDistanceLabel.visible = showDistanceLabel;
if (showDistanceLabel) {
window.questDistanceLabel.x = labelX;
window.questDistanceLabel.y = labelY;
window.questDistanceLabel.setText(labelText);
window.questDistanceLabel.alpha = 0.9 + Math.sin(LK.ticks * 0.1) * 0.1;
window.questDistanceLabel.size = Math.round(unifiedFontSize * 0.9);
window.questDistanceLabel.zIndex = 9999;
}
}
};
// Defensive: Override LK.showGameOver to do nothing except for Reset button
(function () {
var origShowGameOver = LK.showGameOver;
LK.showGameOver = function () {
// Only allow Game Over if called from Reset button (by checking stack)
var err = new Error();
var stack = (err.stack || "").toString();
if (stack.indexOf("game._resetBtn") !== -1) {
origShowGameOver.apply(LK, arguments);
}
// Otherwise, do nothing (no Game Over on death)
};
})();
Uzay temalı global Cevher ticareti, gerçekçi, Altında "Trade" yazsın. In-Game asset. High contrast. No shadows
Uzay temalı global Cevher ticareti, uzay istasyonu, gerçekçi, Altında "Space Stations" yazsın. In-Game asset. High contrast. No shadows
Uzay temalı global Cevher deposu, uzay kargosu, gerçekçi, Altında "Storage" yazsın. In-Game asset. High contrast. No shadows
Uzay temalı Gemi Geliştirme, Tamirci İstasyonu, gerçekçi, Altında "Upgrade" yazsın. In-Game asset. High contrast. No shadows
Uzay temalı global Achievements, gerçekçi, Altında "Achievements" yazsın. In-Game asset. High contrast. No shadows
Uzay temalı, içi altın dolu kapağı açık kasa, gerçekçi, In-Game asset. High contrast. No shadows
Uzay temalı Spaceship Crew, gerçekçi, Altında "crew" yazsın. In-Game asset. High contrast. No shadows
Uzay temalı Savaş Gemisi, gerçekçi, yazısız üstten görünüm. In-Game asset. High contrast. No shadows
Uzay temalı Savaş Gemisi, gerçekçi, yazısız üstten görünüm. In-Game asset. High contrast. No shadows
Uzay temalı altın coin, gerçekçi, yazısız üstten görünüm. In-Game asset. High contrast. No shadows
Uzay temalı Savaş Gemisi, gerçekçi, yazısız üstten görünüm. In-Game asset. High contrast. No shadows
Uzay temalı Savaş Gemisi, gerçekçi, yazısız üstten görünüm. In-Game asset. High contrast. No shadows
Uzay temalı Savaş Gemisi, gerçekçi, yazısız üstten görünüm. In-Game asset. High contrast. No shadows
Uzay temalı Savaş Gemisi, gerçekçi, yazısız üstten görünüm. In-Game asset. High contrast. No shadows
Uzay temalı Savaş Gemisi, gerçekçi, yazısız üstten görünüm. In-Game asset. High contrast. No shadows
Uzay temalı Savaş Gemisi, gerçekçi, yazısız üstten görünüm. In-Game asset. High contrast. No shadows
Uzay temalı Savaş Gemisi, gerçekçi, yazısız üstten görünüm. In-Game asset. High contrast. No shadows
Uzay temalı asteroid, üzerinde cevherler bulunsun, gerçekçi, yazısız üstten görünüm. In-Game asset. High contrast. No shadows