User prompt
Harita yine sınırsız olmaya devam etsin ancak Koordinat içeren; etkinlik, görev ve oyunun bilinmeyen gizli bina ve özelliklerine ulaşmak imkansız olmasın. En fazla mesafe 2 dakika sürecek kadar uzaklıkta olsun. Ona göre görevleri ve etkinlikleri oluştur.
User prompt
İmdat çağrısı, ve diğer koordinat içeren etkinlik, görev vs. Giderken Kalan mesafe küçük bir yazı ile hedefin olduğu kenarda yazsın.
User prompt
Panel kapanınca neden panel içinde ki yazılar ekranda kalıyor. Sorunu düzelt
User prompt
Yazı fontu ve boyutunu %10 oranında büyüt.
User prompt
Panel içinde ki yazı ve buton font boyutunu, Wave font boyutu ile aynı yap.
User prompt
Yazı fontunu wawe yazı fontu gibi yap.
User prompt
Panel içinde ki, yazı ve butonları hizalı olacak şekilde yeniden boyutlandır.
User prompt
Bu paneli %50 oranında aşağı ve yukarı doğru, %25 oranında yana doğru büyüt. Arkaplan da büyüt.
User prompt
Panel içeriği hizalı olacak şekilde, panelin boyutunu ve arkaplan resmini büyüt.
User prompt
Her seviyede, aynı özellikleri 2 kat maliyete alma imkanı olsun.
User prompt
Panelin kapat butonunu, panel başlığı yukarısına taşı.
User prompt
Bu paneli %25 oranında aşağı ve yukarı doğru büyüt. Arkaplan da büyüt.
User prompt
Bu panel boyutunu ve arkaplan resmini %50 oranında büyüt.
User prompt
Bu panelin boyutunu aşağı doğru %50 oranında büyüt. İçinde ki, yazı ve butonları panele sığacak şekilde fontla.
User prompt
Bu panelin boyutunu aşağı doğru %50 oranında büyüt. İçinde ki, yazı ve butonları panele sığacak şekilde fontla.
User prompt
Bu açılan panelin içini hizalı şekilde yeniden yerleştir. Arkaplanını ve boyutunu da içine göre yeniden boyutlandır.
User prompt
Karakter üzerine basınca bir panel açılsın, orada yükseltmeler ve can satın alma butonları olsun.
User prompt
Heath %100 altına düşünce, üzerine tıklayarak hammadde ve coins ile tamir edebilelim.
User prompt
Herhangi bir "terk edilmiş gemi" tarzı Etkinlik olduğunda hedefe ulaşana kadar, koordinat görevlerinde olduğu gibi küçük ok ile göstermeye devam etsin.
User prompt
Heath azaldığında, hammadde ve coins karşılığı tamir edenişelim.
User prompt
Bütün görev sistemini elden geçir. Koordinat olan görevlerin tamamında, ekran kenarında, küçük bir ok ile gösterilsin.
User prompt
Zaman yamulması! Tarzı bilgi yazılarını %10 oranında büyüt.
User prompt
Nebula! tarzı yazıların boyutunu Wave boyutu gibi yap.
User prompt
''Please defeat pirate #unkdown'' yazıyor. burada bilinmeyen yazı yazmasını düzenle. Yada yakında ki korsanlara rastgele isim ver ve görevin yakında ki korsan ile alakalı yazmasını sağla.
User prompt
''Please defeat pirate #unkdown'' yazıyor. burada yazı yazmasını için düzenle.
/**** * 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; } for (var i = 0; i < boostParticles.length; i++) { boostParticles[i].x -= dx / dist * pull; boostParticles[i].y -= dy / dist * pull; } 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 }); var questTypes = ['trade', 'delivery', 'explore', 'escort', 'hunt', 'puzzle', 'defend']; // 10% şansla yeni 'defend' questType ata, yoksa normal random if (Math.random() < 0.10) { self.questType = 'defend'; } else { self.questType = questTypes[Math.floor(Math.random() * (questTypes.length - 1))]; } self.questActive = true; self.questProgress = 0; self.questTarget = null; self.reward = Math.floor(Math.random() * 80) + 30; self.dialogueStep = 0; self.hasTraded = false; 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); self.rpgMood = Math.random() < 0.5 ? "friendly" : "neutral"; self.rpgInventory = { metal: Math.floor(Math.random() * 10), energy: Math.floor(Math.random() * 10), coins: Math.floor(Math.random() * 30) }; self.rpgTradeOffer = { give: Math.random() < 0.5 ? "metal" : "energy", giveAmount: Math.floor(Math.random() * 5) + 1, want: Math.random() < 0.5 ? "energy" : "metal", wantAmount: Math.floor(Math.random() * 5) + 1 }; // --- AI/Quest logic --- self.update = function () { // 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; // --- Defend quest: spawn pirates, request help, handle accept/reject, rep and reward --- if (self.questActive && self.questType === 'defend') { // 1. Eğer henüz korsan saldırısı başlatılmadıysa, başlat if (!self._defendStarted) { // 3-5 korsan spawn et, NPC'yi hedeflesin var squadCount = 3 + Math.floor(Math.random() * 3); self._defendPirates = spawnPirateSquad(self.x, self.y, squadCount, self); self._defendStarted = true; self._defendHelpRequested = false; self._defendHelpAccepted = undefined; // undefined: karar verilmedi, true: kabul, false: reddedildi self._defendHelpPanelShown = false; self._defendPiratesAlive = squadCount; self._defendRewardGiven = false; self._defendPirateDestroyed = 0; self._defendPirateDestroyedLast = 0; self._defendPirateDestroyedTicks = 0; self._defendPirateDestroyedTotal = squadCount; self._defendPirateDestroyedList = []; self._defendPirateDestroyedRepGiven = false; } // 2. Eğer oyuncu yakınsa ve yardım isteği henüz gösterilmediyse, Accept/Reject panelini göster var playerDist = Math.sqrt(Math.pow(ship.x - self.x, 2) + Math.pow(ship.y - self.y, 2)); if (!self._defendHelpPanelShown && playerDist < 180 && self._defendHelpAccepted === undefined) { // Accept/Reject paneli göster if (!self._questDecisionPanel) { // Remove any previous quest panel if (game._questDecisionPanel && game._questDecisionPanel.parent) { game._questDecisionPanel.parent.removeChild(game._questDecisionPanel); game._questDecisionPanel = null; } if (game._questDecisionAcceptBtn && game._questDecisionAcceptBtn.parent) { game._questDecisionAcceptBtn.parent.removeChild(game._questDecisionAcceptBtn); game._questDecisionAcceptBtn = null; } if (game._questDecisionRejectBtn && game._questDecisionRejectBtn.parent) { game._questDecisionRejectBtn.parent.removeChild(game._questDecisionRejectBtn); game._questDecisionRejectBtn = null; } // Panel background var panel = LK.getAsset('resource', { anchorX: 0.5, anchorY: 0.5, x: ship.x, y: ship.y - 180, scaleX: 7, scaleY: 2, tint: 0x222244 }); // Quest text var questText = new Text2("Korsanlar saldırıyor! Yardım eder misin?", { size: 38, fill: 0xffffff, align: "center" }); questText.anchor.set(0.5, 0.5); questText.x = ship.x; questText.y = ship.y - 200; // Accept button var acceptBtn = new Text2("Yardım Et", { size: 44, fill: 0x00ff99, align: "center" }); acceptBtn.anchor.set(0.5, 0.5); acceptBtn.x = ship.x - 100; acceptBtn.y = ship.y - 120; // Reject button var rejectBtn = new Text2("Yardım Etme", { size: 44, fill: 0xff4444, align: "center" }); rejectBtn.anchor.set(0.5, 0.5); rejectBtn.x = ship.x + 100; rejectBtn.y = ship.y - 120; // Add to game game.addChild(panel); game.addChild(questText); game.addChild(acceptBtn); game.addChild(rejectBtn); // Store references for cleanup self._questDecisionPanel = panel; self._questDecisionText = questText; self._questDecisionAcceptBtn = acceptBtn; self._questDecisionRejectBtn = rejectBtn; game._questDecisionPanel = panel; game._questDecisionAcceptBtn = acceptBtn; game._questDecisionRejectBtn = rejectBtn; game._questDecisionText = questText; game._questDecisionNPC = self; acceptBtn._isQuestAcceptBtn = true; rejectBtn._isQuestRejectBtn = true; acceptBtn._questNPC = self; rejectBtn._questNPC = self; acceptBtn._questType = self.questType; rejectBtn._questType = self.questType; } self._defendHelpPanelShown = true; } // 3. Oyuncu Accept/Reject panelinden karar verirse, _defendHelpAccepted güncellenir (game.down'da) // 4. Eğer yardım kabul edildiyse, korsanlar oyuncuya ve NPC'ye saldırır, oyuncu korsanları öldürmeli if (self._defendHelpAccepted === true) { // Korsanlar hem NPC'ye hem oyuncuya saldırır, oyuncu korsanları öldürmeli // Korsanlar update fonksiyonunda zaten NPC'yi hedefliyor // Eğer tüm korsanlar öldüyse, ödül ver ve rep artır var alive = 0; for (var i = 0; i < self._defendPirates.length; i++) { if (!self._defendPirates[i]._destroyed) alive++; } if (alive === 0 && !self._defendRewardGiven) { // Görev tamamlandı, ödül ver playerCoins += self.reward + 50; playerGoodRep += 10; self.questProgress = 1; self._defendRewardGiven = true; questsCompleted++; // Görev tamamlandı mesajı göster var completeLabel = new Text2("NPC kurtarıldı! Ödül: " + (self.reward + 50) + " coin\n+10 İyi Rep", { size: 32, fill: 0x00ff99, align: "center" }); completeLabel.anchor.set(0.5, 0.5); completeLabel.x = self.x; completeLabel.y = self.y + 110; game.addChild(completeLabel); self._npcInteractionLabel = completeLabel; self._npcInteractionLabelExpire = LK.ticks + 150; self.pauseUntil = LK.ticks + 120; self.questActive = false; self._questCompleteShown = true; updateUI(); saveProgress(); } } // 5. Eğer yardım reddedildiyse, korsanlar sadece NPC'ye saldırır, NPC yok edilirse kötü rep ver if (self._defendHelpAccepted === false) { // Korsanlar sadece NPC'yi hedefler var alive = 0; for (var i = 0; i < self._defendPirates.length; i++) { if (!self._defendPirates[i]._destroyed) alive++; } // NPC öldüyse ve rep verilmediyse if (self.health !== undefined && self.health <= 0 && !self._defendPirateDestroyedRepGiven) { playerBadRep += 10; self._defendPirateDestroyedRepGiven = true; // Kötü rep mesajı var failLabel = new Text2("NPC yok edildi!\n+10 Kötü Rep", { size: 32, fill: 0xff4444, align: "center" }); failLabel.anchor.set(0.5, 0.5); failLabel.x = self.x; failLabel.y = self.y + 110; game.addChild(failLabel); self._npcInteractionLabel = failLabel; self._npcInteractionLabelExpire = LK.ticks + 150; self.pauseUntil = LK.ticks + 120; self.questActive = false; self._questCompleteShown = true; updateUI(); saveProgress(); } } } // --- RPG/Quest/Adventure logic: update quest progress if active --- if (self.questActive && self.questType === 'explore' && self.questTarget) { // If player is close to quest target, complete quest var dx = ship.x - self.questTarget.x; var dy = ship.y - self.questTarget.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < 80) { self.questProgress = 1; } } if (self.questActive && self.questType === 'escort' && self.questTarget) { // Oyuncu NPC'ye yakınsa, NPC hedefe doğru hareket etmeye başlasın, uzaksa beklesin var playerDist = Math.sqrt(Math.pow(ship.x - self.x, 2) + Math.pow(ship.y - self.y, 2)); if (self.questProgress === 0) { if (playerDist < 220) { // Hedefe doğru hareket et var tdx = self.questTarget.x - self.x; var tdy = self.questTarget.y - self.y; var tdist = Math.sqrt(tdx * tdx + tdy * tdy); if (tdist > 10) { self.x += tdx / tdist * self.moveSpeed; self.y += tdy / tdist * self.moveSpeed; self.moveAngle = Math.atan2(tdy, tdx); } self._escortWaiting = false; } else { // Oyuncu uzaksa bekle, "Bekliyorum..." mesajı göster if (!self._escortWaiting) { if (self._npcText && self._npcText.parent) { self._npcText.parent.removeChild(self._npcText); } self._npcText = new Text2(self.rpgName + ": Seni bekliyorum, lütfen yakınımda kal!", { size: 32, fill: 0x00ffcc, align: "center" }); self._npcText.anchor.set(0.5, 1); self._npcText.x = self.x; self._npcText.y = self.y - 70; if (game && game.addChild) game.addChild(self._npcText); self._escortWaiting = true; } } } // Eğer NPC hedefe ulaştıysa görevi tamamla var dx = self.x - self.questTarget.x; var dy = self.y - self.questTarget.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < 80) { self.questProgress = 1; // Hedefe ulaşınca bekleme mesajını kaldır if (self._npcText && self._npcText.parent) { self._npcText.parent.removeChild(self._npcText); self._npcText = null; } self._escortWaiting = false; } } if (self.questActive && self.questType === 'hunt') { // Avcılık görevi başlatıldıysa, görev süresi ve hedef sayısı belirle if (!self._huntStarted) { // Görev kabul edildiğinde başlatılır self._huntStarted = true; // Görev süresi (ör: 30 saniye = 1800 tick) self._huntTimeLimit = 1800 + Math.floor(Math.random() * 600); // 30-40 sn arası self._huntTimeStart = LK.ticks; // Kaç korsan öldürülmesi gerektiği self._huntTargetCount = 2 + Math.floor(Math.random() * 3); // 2-4 arası self._huntKilled = 0; self._huntTargetList = []; // Hedef korsanları seç var availablePirates = []; for (var i = 0; i < pirates.length; i++) { if (!pirates[i]._destroyed) availablePirates.push(pirates[i]); } // Eğer yeterli korsan yoksa, yeni korsan spawn et while (availablePirates.length < self._huntTargetCount) { spawnPirate(); for (var i = 0; i < pirates.length; i++) { if (!pirates[i]._destroyed && availablePirates.indexOf(pirates[i]) === -1) { availablePirates.push(pirates[i]); } } } // Hedef korsanları seç for (var i = 0; i < self._huntTargetCount; i++) { var p = availablePirates[i % availablePirates.length]; // Limit pirate spawn distance to max 2 minutes of travel var maxTravelTime = 120; var maxDistance = (ship && ship.speed ? ship.speed : 5) * 60 * maxTravelTime; var distToNPC = Math.sqrt(Math.pow(p.x - self.x, 2) + Math.pow(p.y - self.y, 2)); if (distToNPC > maxDistance) { // Move pirate closer to NPC var angle = Math.atan2(p.y - self.x, p.x - self.x); p.x = self.x + Math.cos(angle) * (Math.random() * (maxDistance * 0.5) + 400); p.y = self.y + Math.sin(angle) * (Math.random() * (maxDistance * 0.5) + 400); } self._huntTargetList.push(p); } self.questTarget = self._huntTargetList[0]; self._huntCurrentTargetIndex = 0; self._huntComplete = false; self._huntFailed = false; } // Görev süresi kontrolü var elapsed = LK.ticks - self._huntTimeStart; if (!self._huntComplete && !self._huntFailed && elapsed > self._huntTimeLimit) { // Süre doldu, görev başarısız self._huntFailed = true; self.questActive = false; self.questProgress = -1; // Kısa süreli başarısızlık mesajı var failLabel = new Text2("Av görevi başarısız! Süre doldu.", { size: 32, fill: 0xff4444, align: "center" }); failLabel.anchor.set(0.5, 0.5); failLabel.x = self.x; failLabel.y = self.y + 110; game.addChild(failLabel); self._npcInteractionLabel = failLabel; self._npcInteractionLabelExpire = LK.ticks + 150; self.pauseUntil = LK.ticks + 120; } // Görev başarısızsa, başka işlem yapma if (self._huntFailed) return; // Hedef korsan öldürüldüyse, bir sonrakine geç if (self._huntTargetList && self._huntCurrentTargetIndex < self._huntTargetList.length) { var currentTarget = self._huntTargetList[self._huntCurrentTargetIndex]; if (currentTarget && currentTarget._destroyed) { self._huntKilled++; self._huntCurrentTargetIndex++; if (self._huntCurrentTargetIndex < self._huntTargetList.length) { self.questTarget = self._huntTargetList[self._huntCurrentTargetIndex]; } else { self.questTarget = null; } } } // Görev tamamlandı mı? if (!self._huntComplete && self._huntKilled >= self._huntTargetCount) { self._huntComplete = true; self.questProgress = 1; self.questActive = false; playerCoins += self.reward + 30; questsCompleted++; var completeLabel = new Text2("Av görevi tamamlandı! Ödül: " + (self.reward + 30) + " coin", { size: 32, fill: 0x00ff99, align: "center" }); completeLabel.anchor.set(0.5, 0.5); completeLabel.x = self.x; completeLabel.y = self.y + 110; game.addChild(completeLabel); self._npcInteractionLabel = completeLabel; self._npcInteractionLabelExpire = LK.ticks + 150; self.pauseUntil = LK.ticks + 120; updateUI(); saveProgress(); } // Hedef korsan varsa, ona saldır if (self.questTarget && !self.questTarget._destroyed) { var dx = self.questTarget.x - self.x; var dy = self.questTarget.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); // Saldırı mesafesi %10 arttırıldı (120 -> 132) if (dist > 132) { self.x += dx / dist * self.moveSpeed * 1.2; self.y += dy / dist * self.moveSpeed * 1.2; self.moveAngle = Math.atan2(dy, dx); } // Saldırı: NPC ateş etsin (her 40 tickte bir) if (!self._lastAttack || LK.ticks - self._lastAttack > 40) { var bullet = new Bullet(); bullet.x = self.x; bullet.y = self.y; var angle = Math.atan2(self.questTarget.y - self.y, self.questTarget.x - self.x); bullet.directionX = Math.cos(angle); bullet.directionY = Math.sin(angle); bullet.rotation = angle + Math.PI / 2; bullets.push(bullet); if (game && game.addChild) game.addChild(bullet); self._lastAttack = LK.ticks; } // Eğer oyuncu da yakınsa, birlikte saldırı efekti // Saldırı mesafesi %10 arttırıldı (200 -> 220) var playerDist = Math.sqrt(Math.pow(ship.x - self.questTarget.x, 2) + Math.pow(ship.y - self.questTarget.y, 2)); if (playerDist < 220 && dist < 220) { self.questTarget.moveAngle = Math.atan2(ship.y - self.questTarget.y, ship.x - self.questTarget.x); } } } if (self.questActive && self.questType === 'puzzle') { // Simulate puzzle solved after some time if (LK.ticks % 600 === 0) { self.questProgress = 1; } } }; // --- RPG/Adventure/Trade: interaction method for player tap/close --- self.interact = function () { // Dialogue/quest/trade logic if (!self.questActive) return "I'm just exploring the stars!"; // Helper for EXP gain and level up function gainEXP(amount) { playerEXP += amount; var leveledUp = false; while (playerEXP >= expToNext(playerLevel)) { playerEXP -= expToNext(playerLevel); playerLevel++; leveledUp = true; } updateUI(); if (leveledUp) { LK.effects.flashObject(ship, 0x00ffcc, 800); return "Level Up! Now Level " + playerLevel + "!"; } return null; } if (self.questType === 'trade') { if (!self.hasTraded) { // Offer trade if (self.rpgTradeOffer.give === 'metal' && playerMetal >= self.rpgTradeOffer.wantAmount) { playerMetal -= self.rpgTradeOffer.wantAmount; playerEnergy += self.rpgTradeOffer.giveAmount; self.hasTraded = true; var expMsg = gainEXP(10 + Math.floor(Math.random() * 10)); return self.rpgName + ": Thanks for the trade! +" + self.rpgTradeOffer.giveAmount + " energy!" + (expMsg ? "\n" + expMsg : ""); } else if (self.rpgTradeOffer.give === 'energy' && playerEnergy >= self.rpgTradeOffer.wantAmount) { playerEnergy -= self.rpgTradeOffer.wantAmount; playerMetal += self.rpgTradeOffer.giveAmount; self.hasTraded = true; var expMsg = gainEXP(10 + Math.floor(Math.random() * 10)); return self.rpgName + ": Thanks for the trade! +" + self.rpgTradeOffer.giveAmount + " metal!" + (expMsg ? "\n" + expMsg : ""); } else { return self.rpgName + ": I can trade " + self.rpgTradeOffer.giveAmount + " " + self.rpgTradeOffer.give + " for " + self.rpgTradeOffer.wantAmount + " " + self.rpgTradeOffer.want + "."; } } else { return self.rpgName + ": Good luck out there!"; } } if (self.questType === 'delivery') { if (self.questProgress === 0) { // Assign delivery quest: go to a random point if (!self.questTarget) { // Limit quest target distance to max 2 minutes of travel (approx 60*ship.speed*2 px) var maxTravelTime = 120; // seconds var maxDistance = (ship && ship.speed ? ship.speed : 5) * 60 * maxTravelTime; // px var angle = Math.random() * Math.PI * 2; var dist = Math.random() * (maxDistance * 0.5) + 400; // 400px min, up to maxDistance/2 self.questTarget = { x: self.x + Math.cos(angle) * dist, y: self.y + Math.sin(angle) * dist }; return self.rpgName + ": Can you deliver this package to (" + Math.floor(self.questTarget.x) + "," + Math.floor(self.questTarget.y) + ")?"; } else { var dx = ship.x - self.questTarget.x; var dy = ship.y - self.questTarget.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < 80) { self.questProgress = 1; playerCoins += self.reward; questsCompleted++; var expMsg = gainEXP(40 + Math.floor(Math.random() * 20)); return self.rpgName + ": Delivery complete! Reward: " + self.reward + " coins!" + (expMsg ? "\n" + expMsg : ""); } else { return self.rpgName + ": Please deliver to (" + Math.floor(self.questTarget.x) + "," + Math.floor(self.questTarget.y) + ")"; } } } else { return self.rpgName + ": Thank you for your help!"; } } if (self.questType === 'explore') { if (self.questProgress === 0) { if (!self.questTarget) { // Limit quest target distance to max 2 minutes of travel var maxTravelTime = 120; var maxDistance = (ship && ship.speed ? ship.speed : 5) * 60 * maxTravelTime; var angle = Math.random() * Math.PI * 2; var dist = Math.random() * (maxDistance * 0.5) + 400; self.questTarget = { x: self.x + Math.cos(angle) * dist, y: self.y + Math.sin(angle) * dist }; return self.rpgName + ": Can you explore the area at (" + Math.floor(self.questTarget.x) + "," + Math.floor(self.questTarget.y) + ")?"; } else { var dx = ship.x - self.questTarget.x; var dy = ship.y - self.questTarget.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < 80) { self.questProgress = 1; playerCoins += self.reward; questsCompleted++; var expMsg = gainEXP(30 + Math.floor(Math.random() * 15)); return self.rpgName + ": Thanks for exploring! Reward: " + self.reward + " coins!" + (expMsg ? "\n" + expMsg : ""); } else { return self.rpgName + ": Please explore (" + Math.floor(self.questTarget.x) + "," + Math.floor(self.questTarget.y) + ")"; } } } else { return self.rpgName + ": You are a true explorer!"; } } if (self.questType === 'escort') { if (self.questProgress === 0) { if (!self.questTarget) { // Limit quest target distance to max 2 minutes of travel var maxTravelTime = 120; var maxDistance = (ship && ship.speed ? ship.speed : 5) * 60 * maxTravelTime; var angle = Math.random() * Math.PI * 2; var dist = Math.random() * (maxDistance * 0.5) + 400; self.questTarget = { x: self.x + Math.cos(angle) * dist, y: self.y + Math.sin(angle) * dist }; return self.rpgName + ": Can you escort me to (" + Math.floor(self.questTarget.x) + "," + Math.floor(self.questTarget.y) + ")?"; } else { var dx = self.x - self.questTarget.x; var dy = self.y - self.questTarget.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < 80) { self.questProgress = 1; playerCoins += self.reward; questsCompleted++; var expMsg = gainEXP(35 + Math.floor(Math.random() * 15)); return self.rpgName + ": Safe arrival! Reward: " + self.reward + " coins!" + (expMsg ? "\n" + expMsg : ""); } else { // Move toward target if player is close var pdx = ship.x - self.x; var pdy = ship.y - self.y; var pdist = Math.sqrt(pdx * pdx + pdy * pdy); if (pdist < 200) { var tdx = self.questTarget.x - self.x; var tdy = self.questTarget.y - self.y; var tdist = Math.sqrt(tdx * tdx + tdy * tdy); if (tdist > 10) { self.x += tdx / tdist * self.moveSpeed; self.y += tdy / tdist * self.moveSpeed; } } return self.rpgName + ": Please escort me to (" + Math.floor(self.questTarget.x) + "," + Math.floor(self.questTarget.y) + ")"; } } } else { return self.rpgName + ": Thank you for the escort!"; } } if (self.questType === 'hunt') { if (self.questProgress === 0) { if (!self.questTarget) { // Assign a random pirate as target, and give pirates random names if not already set if (pirates.length > 0) { // Pirate name pool var pirateNames = ["Kaptan Kara", "Uzay Korsanı Zed", "Astro Jack", "Korsan Nova", "Kaptan Yıldız", "Korsan Rex", "Korsan Luna", "Korsan Vex", "Korsan Orion", "Korsan Vega"]; // Assign names to pirates if not already named for (var i = 0; i < pirates.length; i++) { if (!pirates[i].rpgName || pirates[i].rpgName.indexOf("Korsan-") === 0 || pirates[i].rpgName.indexOf("BaseKorsan-") === 0) { pirates[i].rpgName = pirateNames[Math.floor(Math.random() * pirateNames.length)]; } } self.questTarget = pirates[Math.floor(Math.random() * pirates.length)]; return self.rpgName + ": " + self.questTarget.rpgName + " adlı korsanı yenebilir misin?"; } else { return self.rpgName + ": Yakında korsan yok, sonra tekrar gel!"; } } else { if (self.questTarget._destroyed) { self.questProgress = 1; playerCoins += self.reward; questsCompleted++; var expMsg = gainEXP(50 + Math.floor(Math.random() * 20)); return self.rpgName + ": Korsan yenildi! Ödül: " + self.reward + " coin!" + (expMsg ? "\n" + expMsg : ""); } else { return self.rpgName + ": Lütfen " + (self.questTarget.rpgName || "bilinmeyen korsan") + " adlı korsanı yen."; } } } else { return self.rpgName + ": Gerçek bir kahramansın!"; } } if (self.questType === 'puzzle') { if (self.questProgress === 0) { return self.rpgName + ": Solve my puzzle! (Wait a bit...)"; } else { playerCoins += self.reward; questsCompleted++; self.questProgress = 2; var expMsg = gainEXP(25 + Math.floor(Math.random() * 10)); return self.rpgName + ": Puzzle solved! Reward: " + self.reward + " coins!" + (expMsg ? "\n" + expMsg : ""); } } return self.rpgName + ": Safe travels!"; }; 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 }); self.type = Math.random() < 0.5 ? 'metal' : 'energy'; self.amount = Math.floor(Math.random() * 5) + 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.boostSpeed = 0; self.boostCooldown = 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; LK.showGameOver(); } }; 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); } // Boost cooldown if (self.boostCooldown > 0) { self.boostCooldown--; } if (self.boostSpeed > 0) { self.boostSpeed -= 0.2; } }; 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; }); // 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; } for (var i = 0; i < boostParticles.length; i++) { boostParticles[i].x -= dx2; boostParticles[i].y -= dy2; } 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 ****/ // Game variables var ship; var joystickBase; var joystickHandle; var isDragging = false; var bullets = []; var enemyBullets = []; var npcs = []; var pirates = []; var coins = []; var resources = []; var stars = []; var asteroids = []; var upgradeStations = []; var boostParticles = []; var explosions = []; var blackHoles = []; var wormholes = []; var tradeStations = []; var pirateBases = []; // NEW: array for pirate bases var tradeText = new Text2('', { size: 40, fill: 0x00ff99 }); // 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; } 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.anchor.set(0.5, 0); tradeText.y = 180; LK.gui.top.addChild(tradeText); var camera = { x: 0, y: 0 }; // --- Reputation system --- var playerGoodRep = storage.playerGoodRep || 0; var playerBadRep = storage.playerBadRep || 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; var playerMetal = storage.metal || 0; var playerEnergy = storage.energy || 0; var questsCompleted = storage.questsCompleted || 0; // 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); var resourceText = new Text2('Metal: ' + playerMetal + ' Energy: ' + playerEnergy, { size: unifiedFontSize, fill: 0xFFFFFF }); resourceText.anchor.set(0, 0); resourceText.x = 120; resourceText.y = 80; LK.gui.topLeft.addChild(resourceText); 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); var boostText = new Text2('BOOST READY', { size: unifiedFontSize, fill: 0x00FFFF }); boostText.anchor.set(0.5, 0); boostText.y = 110; LK.gui.top.addChild(boostText); var waveText = new Text2('Wave: 1', { size: unifiedFontSize, fill: 0xFFFFFF }); waveText.anchor.set(1, 0); waveText.x = -20; waveText.y = 20; LK.gui.topRight.addChild(waveText); // --- RESET BUTTON (bottom right) --- var resetBtn = new Text2('Reset', { size: 44, fill: 0xff4444, font: "'Heath', Impact, 'Arial Black', Tahoma", // Heath-like font align: "center" }); resetBtn.anchor.set(1, 1); // bottom right resetBtn.x = -40; resetBtn.y = -40; LK.gui.bottomRight.addChild(resetBtn); // Touch/click handler for reset button resetBtn._isResetBtn = true; game._resetBtn = resetBtn; // Level/EXP system var playerLevel = storage.playerLevel || 1; var playerEXP = storage.playerEXP || 0; var expToNext = function expToNext(lv) { return 100 + (lv - 1) * 50; }; var expText = new Text2('Level: ' + playerLevel + ' EXP: ' + playerEXP + '/' + expToNext(playerLevel), { size: unifiedFontSize, fill: 0x00ffcc }); expText.anchor.set(1, 0); expText.x = -20; expText.y = 80; LK.gui.topRight.addChild(expText); // Move coordinateText to the left of waveText, decrease its size by 30%, and update its position and size in real time var coordinateText = new Text2('X: 0 Y: 0', { size: unifiedFontSize, // 30% smaller than Level text fill: 0xcccccc }); coordinateText.anchor.set(1, 0.5); // right center of the text // Position coordinateText to the left of waveText coordinateText.x = waveText.x - waveText.width - 30; coordinateText.y = waveText.y + waveText.height / 2; LK.gui.topRight.addChild(coordinateText); // 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 for (var i = 0; i < 50; i++) { spawnStar(); } // Helper functions function spawnStar() { var star = new Star(); // Spawn from edges of visible area var edge = Math.floor(Math.random() * 4); switch (edge) { case 0: // Top star.x = ship.x + (Math.random() - 0.5) * 2500; star.y = ship.y - 1500; break; case 1: // Right star.x = ship.x + 1500; star.y = ship.y + (Math.random() - 0.5) * 2500; break; case 2: // Bottom star.x = ship.x + (Math.random() - 0.5) * 2500; star.y = ship.y + 1500; break; case 3: // Left star.x = ship.x - 1500; star.y = ship.y + (Math.random() - 0.5) * 2500; break; } 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; // 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; }, 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); } function spawnUpgradeStation() { var station = new UpgradeStation(); station.x = ship.x + (Math.random() - 0.5) * 3000; station.y = ship.y + (Math.random() - 0.5) * 3000; upgradeStations.push(station); game.addChild(station); } function spawnTradeStation() { var ts = new TradeStation(); // Spawn from edges of visible area var edge = Math.floor(Math.random() * 4); switch (edge) { case 0: ts.x = ship.x + (Math.random() - 0.5) * 2000; ts.y = ship.y - 1500; break; case 1: ts.x = ship.x + 1500; ts.y = ship.y + (Math.random() - 0.5) * 2000; break; case 2: ts.x = ship.x + (Math.random() - 0.5) * 2000; ts.y = ship.y + 1500; break; case 3: ts.x = ship.x - 1500; ts.y = ship.y + (Math.random() - 0.5) * 2000; break; } tradeStations.push(ts); game.addChild(ts); } 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); } } function spawnBlackHole() { var bh = new BlackHole(); // Spawn far from ship, random edge var edge = Math.floor(Math.random() * 4); switch (edge) { case 0: bh.x = ship.x + (Math.random() - 0.5) * 2000; bh.y = ship.y - 1700; break; case 1: bh.x = ship.x + 1700; bh.y = ship.y + (Math.random() - 0.5) * 2000; break; case 2: bh.x = ship.x + (Math.random() - 0.5) * 2000; bh.y = ship.y + 1700; break; case 3: bh.x = ship.x - 1700; bh.y = ship.y + (Math.random() - 0.5) * 2000; break; } blackHoles.push(bh); game.addChild(bh); } function spawnWormhole() { var wh = new Wormhole(); // Spawn far from ship, random edge var edge = Math.floor(Math.random() * 4); switch (edge) { case 0: wh.x = ship.x + (Math.random() - 0.5) * 2000; wh.y = ship.y - 1700; break; case 1: wh.x = ship.x + 1700; wh.y = ship.y + (Math.random() - 0.5) * 2000; break; case 2: wh.x = ship.x + (Math.random() - 0.5) * 2000; wh.y = ship.y + 1700; break; case 3: wh.x = ship.x - 1700; wh.y = ship.y + (Math.random() - 0.5) * 2000; break; } wormholes.push(wh); game.addChild(wh); } function createBoostParticle() { var particle = LK.getAsset('boostParticle', { anchorX: 0.5, anchorY: 0.5, x: ship.x - Math.cos(ship.rotation - Math.PI / 2) * 50, y: ship.y - Math.sin(ship.rotation - Math.PI / 2) * 50 }); particle.vx = -Math.cos(ship.rotation - Math.PI / 2) * 5 + (Math.random() - 0.5) * 2; particle.vy = -Math.sin(ship.rotation - Math.PI / 2) * 5 + (Math.random() - 0.5) * 2; particle.life = 20; boostParticles.push(particle); game.addChild(particle); } function updateUI() { coinText.setText('Coins: ' + playerCoins); resourceText.setText('Metal: ' + playerMetal + ' Energy: ' + playerEnergy); healthText.setText('Health: ' + ship.health + '/' + ship.maxHealth); shieldText.setText('Shield: ' + Math.floor(ship.shield) + '/' + ship.maxShield); waveText.setText('Wave: ' + (waveNumber + 1)); expText.setText('Level: ' + playerLevel + ' EXP: ' + playerEXP + '/' + expToNext(playerLevel)); // Show rep in GUI if (!window.repText) { window.repText = new Text2('Rep: +' + playerGoodRep + ' / -' + playerBadRep, { size: unifiedFontSize, fill: 0xffffff }); window.repText.anchor.set(1, 0); window.repText.x = -20; window.repText.y = 140; LK.gui.topRight.addChild(window.repText); } window.repText.setText('Rep: +' + playerGoodRep + ' / -' + playerBadRep); // 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; } // Update boost text if (ship.boostCooldown <= 0) { boostText.setText('BOOST READY'); boostText.fill = 0x00ffff; } else { boostText.setText('BOOST: ' + Math.ceil(ship.boostCooldown / 60) + 's'); boostText.fill = 0x888888; } storage.playerLevel = playerLevel; storage.playerEXP = playerEXP; } function saveProgress() { storage.coins = playerCoins; storage.metal = playerMetal; storage.energy = playerEnergy; storage.questsCompleted = questsCompleted; storage.playerGoodRep = playerGoodRep; storage.playerBadRep = playerBadRep; } // Event handlers game.down = function (x, y, obj) { // --- 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.questsCompleted = 0; storage.playerLevel = 1; storage.playerEXP = 0; storage.playerGoodRep = 0; storage.playerBadRep = 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; } } 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; var cbx = cbtn.x, cby = cbtn.y; if (x > cbx - 90 && x < cbx + 90 && y > cby - 40 && y < cby + 40) { 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; 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 var panelWidth = 700; var panelHeight = 340; panelWidth = Math.round(panelWidth * 1.25); // %25 yana büyüt panelHeight = Math.round(panelHeight * 1.5); // %50 yukarı ve aşağı büyüt panelHeight = Math.round(panelHeight * 1.5); // %50 tekrar yukarı ve aşağı büyüt (toplamda %50+%50=2x) 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); 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(100 coin, 10 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: 100, metal: 10, energy: 0 }; var upg1x2 = new Text2("Max Can +20\n(200 coin, 20 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: 200, metal: 20, energy: 0 }; upg1x2._isDoubleCost = true; var upg2 = new Text2("Max Kalkan +10\n(120 coin, 12 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: 120, metal: 12, energy: 0 }; var upg2x2 = new Text2("Max Kalkan +10\n(240 coin, 24 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: 240, metal: 24, energy: 0 }; upg2x2._isDoubleCost = true; var upg3 = new Text2("Hasar +5\n(150 coin, 15 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: 150, metal: 0, energy: 15 }; var upg3x2 = new Text2("Hasar +5\n(300 coin, 30 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: 300, metal: 0, energy: 30 }; upg3x2._isDoubleCost = true; // Buy health button (if not full) var canBuyHealth = ship.health < ship.maxHealth; var buyHealthBtnFont = unifiedFontSize; var buyHealthBtn = new Text2("Canı Doldur (" + Math.max(30, Math.round((ship.maxHealth - ship.health) * 1.5)) + " coin, " + Math.max(2, Math.round((ship.maxHealth - ship.health) / 20)) + " metal, " + Math.max(2, Math.round((ship.maxHealth - ship.health) / 25)) + " 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 = Math.max(30, Math.round((ship.maxHealth - ship.health) * 1.5)); buyHealthBtn._repairCostMetal = Math.max(2, Math.round((ship.maxHealth - ship.health) / 20)); buyHealthBtn._repairCostEnergy = Math.max(2, Math.round((ship.maxHealth - ship.health) / 25)); // Close button var closeBtnFont = unifiedFontSize; var closeBtn = new Text2("Kapat", { size: closeBtnFont, 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 - 90; 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(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.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 if (y < 300 && ship.boostCooldown <= 0) { ship.boostSpeed = 10; ship.boostCooldown = 300; // 5 seconds cooldown if (LK.getSound('boost')) { LK.getSound('boost').play(); } } 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; } } // 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.shipUpgradeCloseBtn && window.shipUpgradeCloseBtn.parent) window.shipUpgradeCloseBtn.parent.removeChild(window.shipUpgradeCloseBtn); 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.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 + ship.boostSpeed; shipDX = dx / 100 * effectiveSpeed; shipDY = dy / 100 * effectiveSpeed; ship.rotation = Math.atan2(dy, dx) + Math.PI / 2; // Create boost particles when boosting if (ship.boostSpeed > 0 && LK.ticks % 2 === 0) { createBoostParticle(); } } } // 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; } for (var i = 0; i < boostParticles.length; i++) { boostParticles[i].x -= shipDX; boostParticles[i].y -= shipDY; } 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); 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); } // Give 1-3 EXP for each pirate killed var pirateExp = 1 + 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); } // 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; } } // 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 for (var k = 0; k < asteroids[j].resources; 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(); } } // Update pirates for (var i = 0; i < pirates.length; i++) { var pirate = pirates[i]; if (pirate._healthBar && pirate._healthBar.update) pirate._healthBar.update(); // Update pirate AI var dist = Math.sqrt(Math.pow(ship.x - pirate.x, 2) + Math.pow(ship.y - pirate.y, 2)); // Eğer bir NPC'nin hunt görevi varsa ve bu korsan hedefse, birlikte saldırı efekti var huntedByNPC = false; for (var n = 0; n < npcs.length; n++) { var npc = npcs[n]; if (npc.questType === 'hunt' && npc.questActive && npc.questTarget === pirate && !pirate._destroyed) { huntedByNPC = true; // NPC'nin saldırı animasyonu için efekt if (!pirate._lastHuntFlash || LK.ticks - pirate._lastHuntFlash > 30) { LK.effects.flashObject(pirate, 0xffcccc, 100); pirate._lastHuntFlash = LK.ticks; } // Eğer oyuncu da yakınsa, korsan hem NPC'ye hem oyuncuya saldırabilir var distToNPC = Math.sqrt(Math.pow(npc.x - pirate.x, 2) + Math.pow(npc.y - pirate.y, 2)); if (distToNPC < 200 && dist < 200) { // Rastgele oyuncuya veya NPC'ye saldır var target = Math.random() < 0.5 ? ship : npc; var angle = Math.atan2(target.y - pirate.y, target.x - pirate.x); pirate.x += Math.cos(angle) * pirate.speed; pirate.y += Math.sin(angle) * pirate.speed; pirate.rotation = angle + Math.PI / 2; // Pirate shooting 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); enemyBullets.push(bullet); game.addChild(bullet); pirate.lastFire = LK.ticks; } continue; } } } // Only chase and attack when very close (within 220 pixels) // Saldırı mesafesi %10 arttırıldı (200 -> 220) if (!huntedByNPC && dist < 220) { // Chase ship when very close var angle = Math.atan2(ship.y - pirate.y, ship.x - pirate.x); pirate.x += Math.cos(angle) * pirate.speed; pirate.y += Math.sin(angle) * pirate.speed; pirate.rotation = angle + Math.PI / 2; // Pirate shooting when very close 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); enemyBullets.push(bullet); game.addChild(bullet); pirate.lastFire = LK.ticks; } } if (dist > 2000) { pirate.destroy(); pirates.splice(i, 1); i--; } } // Update NPCs var npcActive = false; 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; } // Görev tamamlandıysa, NPC'nin etkileşim mesajı ve durumu güncellensin if (npc.questActive && npc.questProgress === 1 && !npc._questCompleteShown) { // Görev tamamlandı mesajı göster var completeLabel = new Text2("Görev tamamlandı!", { size: 36, fill: 0x00ff99, align: "center" }); completeLabel.anchor.set(0.5, 0.5); completeLabel.x = npc.x; completeLabel.y = npc.y + 110; game.addChild(completeLabel); npc._npcInteractionLabel = completeLabel; npc._npcInteractionLabelExpire = LK.ticks + 120; npc._questCompleteShown = true; // NPC kısa süre dursun npc.pauseUntil = LK.ticks + 120; // NPC'nin questActive'ini pasif yap (tekrar etkileşim olmasın) npc.questActive = false; } // RPG/Adventure: If player is close, show interaction UI if (dist < 180) { npcActive = true; // Remove any previous floating text if (npc._npcText && npc._npcText.parent) { npc._npcText.parent.removeChild(npc._npcText); npc._npcText = null; } var npcMsg = ""; if (game._lastNPCTap !== undefined && game._lastNPCTap + 30 > LK.ticks && game._lastNPC !== npc) { // Player tapped recently, interact var msg = npc.interact(); npcMsg = msg; updateUI(); saveProgress(); game._lastNPC = npc; // Pause NPC for 2 seconds (120 ticks) after interaction npc.pauseUntil = LK.ticks + 120; // Also clear tradeText in GUI tradeText.setText(''); // --- Show floating interaction label under NPC for a short duration --- if (msg && typeof msg === "string" && msg.length > 0) { // Remove previous interaction label if any if (npc._npcInteractionLabel && npc._npcInteractionLabel.parent) { npc._npcInteractionLabel.parent.removeChild(npc._npcInteractionLabel); npc._npcInteractionLabel = null; } var interactionLabel = new Text2(msg.split('\n')[0], { size: 30, fill: 0xffffff, align: "center" }); interactionLabel.anchor.set(0.5, 0); interactionLabel.x = npc.x; interactionLabel.y = npc.y + 70; npc._npcInteractionLabel = interactionLabel; game.addChild(interactionLabel); // Set a timer to remove after 2.5 seconds (150 ticks) npc._npcInteractionLabelExpire = LK.ticks + 150; } // --- Show Accept/Reject quest buttons above the ship if NPC is a quest-giver and quest is not yet accepted --- if (npc.questActive && npc.questType !== 'trade' && npc.questProgress === 0 && !npc._questDecisionPanel) { // Remove any previous quest panel if (game._questDecisionPanel && game._questDecisionPanel.parent) { game._questDecisionPanel.parent.removeChild(game._questDecisionPanel); game._questDecisionPanel = null; } if (game._questDecisionAcceptBtn && game._questDecisionAcceptBtn.parent) { game._questDecisionAcceptBtn.parent.removeChild(game._questDecisionAcceptBtn); game._questDecisionAcceptBtn = null; } if (game._questDecisionRejectBtn && game._questDecisionRejectBtn.parent) { game._questDecisionRejectBtn.parent.removeChild(game._questDecisionRejectBtn); game._questDecisionRejectBtn = null; } // Panel background var panel = LK.getAsset('resource', { anchorX: 0.5, anchorY: 0.5, x: ship.x, y: ship.y - 180, scaleX: 7, scaleY: 2, tint: 0x222244 }); // Quest text var questText = new Text2("Görev: " + (npcMsg ? npcMsg.split('\n')[0] : "Bir görev var!"), { size: 38, fill: 0xffffff, align: "center" }); questText.anchor.set(0.5, 0.5); questText.x = ship.x; questText.y = ship.y - 200; // Accept button var acceptBtn = new Text2("Kabul Et", { size: 44, fill: 0x00ff99, align: "center" }); acceptBtn.anchor.set(0.5, 0.5); acceptBtn.x = ship.x - 100; acceptBtn.y = ship.y - 120; // Reject button var rejectBtn = new Text2("Reddet", { size: 44, fill: 0xff4444, align: "center" }); rejectBtn.anchor.set(0.5, 0.5); rejectBtn.x = ship.x + 100; rejectBtn.y = ship.y - 120; // Add to game game.addChild(panel); game.addChild(questText); game.addChild(acceptBtn); game.addChild(rejectBtn); // Store references for cleanup npc._questDecisionPanel = panel; npc._questDecisionText = questText; npc._questDecisionAcceptBtn = acceptBtn; npc._questDecisionRejectBtn = rejectBtn; game._questDecisionPanel = panel; game._questDecisionAcceptBtn = acceptBtn; game._questDecisionRejectBtn = rejectBtn; game._questDecisionText = questText; game._questDecisionNPC = npc; // Accept/Reject tap logic acceptBtn._isQuestAcceptBtn = true; rejectBtn._isQuestRejectBtn = true; acceptBtn._questNPC = npc; rejectBtn._questNPC = npc; acceptBtn._questType = npc.questType; rejectBtn._questType = npc.questType; } // --- NPC Trade Panel Logic --- if (npc.questType === 'trade' && npc.questActive && !npc.hasTraded) { // Show a trade panel above the NPC with offer and tap-to-trade var offer = npc.rpgTradeOffer; var canTrade = false; var tradeMsg = ""; if (offer.give === 'metal' && playerMetal >= offer.wantAmount) { canTrade = true; tradeMsg = "Trade: Give " + offer.wantAmount + " " + offer.want + " for " + offer.giveAmount + " " + offer.give + " (Tap to confirm)"; } else if (offer.give === 'energy' && playerEnergy >= offer.wantAmount) { canTrade = true; tradeMsg = "Trade: Give " + offer.wantAmount + " " + offer.want + " for " + offer.giveAmount + " " + offer.give + " (Tap to confirm)"; } else { tradeMsg = "Trade: Need " + offer.wantAmount + " " + offer.want + " to trade for " + offer.giveAmount + " " + offer.give; } // Remove previous trade panel if any if (npc._npcTradePanel && npc._npcTradePanel.parent) { npc._npcTradePanel.parent.removeChild(npc._npcTradePanel); npc._npcTradePanel = null; } var tradePanel = new Text2(tradeMsg, { size: 36, fill: canTrade ? 0x00ff99 : 0xff8888, align: "center" }); tradePanel.anchor.set(0.5, 0); tradePanel.x = npc.x; tradePanel.y = npc.y + 80; npc._npcTradePanel = tradePanel; game.addChild(tradePanel); // If tapped again within window, perform trade if (canTrade && game._lastNPCTap !== undefined && game._lastNPCTap + 15 > LK.ticks && game._lastNPCTrade !== npc) { // Actually perform trade if (offer.give === 'metal') { playerMetal -= offer.wantAmount; playerEnergy += offer.giveAmount; } else { playerEnergy -= offer.wantAmount; playerMetal += offer.giveAmount; } npc.hasTraded = true; var expMsg = "EXP +" + (10 + Math.floor(Math.random() * 10)); playerEXP += 10 + Math.floor(Math.random() * 10); updateUI(); saveProgress(); // Show confirmation tradePanel.setText("Trade complete!\n" + expMsg); tradePanel.fill = 0x00ffcc; game._lastNPCTrade = npc; } } else { // Remove trade panel if not trading if (npc._npcTradePanel && npc._npcTradePanel.parent) { npc._npcTradePanel.parent.removeChild(npc._npcTradePanel); npc._npcTradePanel = null; } } } else if (!npc.questActive || npc.questProgress > 0) { npcMsg = npc.rpgName + ": " + (npc.questActive ? "Thank you!" : "Safe travels!"); // Remove trade panel if not trading if (npc._npcTradePanel && npc._npcTradePanel.parent) { npc._npcTradePanel.parent.removeChild(npc._npcTradePanel); npc._npcTradePanel = null; } } else { // Show quest/trade offer if (npc.questType === 'trade') { npcMsg = npc.rpgName + ": Trade? Tap to interact."; } else if (npc.questType === 'delivery') { npcMsg = npc.rpgName + ": Delivery quest! Tap to interact."; } else if (npc.questType === 'explore') { npcMsg = npc.rpgName + ": Exploration quest! Tap to interact."; } else if (npc.questType === 'escort') { npcMsg = npc.rpgName + ": Escort quest! Tap to interact."; } else if (npc.questType === 'hunt') { npcMsg = npc.rpgName + ": Hunt quest! Tap to interact."; } else if (npc.questType === 'puzzle') { npcMsg = npc.rpgName + ": Puzzle quest! Tap to interact."; } // Remove trade panel if not trading if (npc._npcTradePanel && npc._npcTradePanel.parent) { npc._npcTradePanel.parent.removeChild(npc._npcTradePanel); npc._npcTradePanel = null; } } // Show floating text above NPC if (npcMsg) { var npcText = new Text2(npcMsg, { size: 38, fill: 0x00ffcc, align: "center" }); npcText.anchor.set(0.5, 1); npcText.x = npc.x; npcText.y = npc.y - 70; // Remove previous if any if (npc._npcText && npc._npcText.parent) { npc._npcText.parent.removeChild(npc._npcText); } npc._npcText = npcText; game.addChild(npcText); } // Remove tradeText from GUI tradeText.setText(''); } else { // Remove floating text if player is not close if (npc._npcText && npc._npcText.parent) { npc._npcText.parent.removeChild(npc._npcText); npc._npcText = null; } } // Remove quest Accept/Reject panel if player moves away from NPC if (npc._questDecisionPanel && dist >= 220) { if (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; } // Remove floating interaction label if expired if (npc._npcInteractionLabel && npc._npcInteractionLabelExpire !== undefined && LK.ticks > npc._npcInteractionLabelExpire) { if (npc._npcInteractionLabel.parent) { npc._npcInteractionLabel.parent.removeChild(npc._npcInteractionLabel); } npc._npcInteractionLabel = null; npc._npcInteractionLabelExpire = undefined; } } if (!npcActive) { game._lastNPC = 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); } } // --- Space Debris Field Event --- // Every 18000 ticks, 10% chance, only one at a time if (!window.debrisField && LK.ticks % 18000 === 0 && Math.random() < 0.1) { var cx = ship.x + (Math.random() - 0.5) * 3000; var cy = ship.y + (Math.random() - 0.5) * 3000; var debris = []; for (var i = 0; i < 15; i++) { var a = new Asteroid(); var angle = Math.random() * Math.PI * 2; var radius = 200 + Math.random() * 200; a.x = cx + Math.cos(angle) * radius; a.y = cy + Math.sin(angle) * radius; a.health = 10 + Math.floor(Math.random() * 20); a.resources = 1 + Math.floor(Math.random() * 3); asteroids.push(a); game.addChild(a); debris.push(a); } var debrisLabel = new Text2("Enkaz Alanı", { size: 36, fill: 0xcccccc, align: "center" }); debrisLabel.anchor.set(0.5, 0); debrisLabel.x = cx; debrisLabel.y = cy + 250; game.addChild(debrisLabel); window.debrisField = { debris: debris, label: debrisLabel, x: cx, y: cy }; } // Remove debris field if all asteroids gone or too far if (window.debrisField) { var allGone = true; for (var i = 0; i < window.debrisField.debris.length; i++) { if (asteroids.indexOf(window.debrisField.debris[i]) !== -1) { allGone = false; break; } } var dist = Math.sqrt(Math.pow(window.debrisField.x - ship.x, 2) + Math.pow(window.debrisField.y - ship.y, 2)); if (allGone || dist > 4000) { if (window.debrisField.label && window.debrisField.label.parent) window.debrisField.label.parent.removeChild(window.debrisField.label); window.debrisField = null; } else { // Keep label above field if (window.debrisField.label) { window.debrisField.label.x = window.debrisField.x; window.debrisField.label.y = window.debrisField.y + 250; } } } // Update upgrade stations for (var i = upgradeStations.length - 1; i >= 0; i--) { var station = upgradeStations[i]; var dist = Math.sqrt(Math.pow(station.x - ship.x, 2) + Math.pow(station.y - ship.y, 2)); if (dist < 100 && playerCoins >= 100) { // Apply random upgrade var upgrade = station.upgrades[Math.floor(Math.random() * station.upgrades.length)]; if (upgrade.name === 'health' && playerMetal >= (upgrade.metalCost || 0)) { ship.maxHealth += 20; ship.health = ship.maxHealth; playerCoins -= upgrade.cost; playerMetal -= upgrade.metalCost || 0; } else if (upgrade.name === 'shield' && playerMetal >= (upgrade.metalCost || 0)) { ship.maxShield += 10; ship.shield = ship.maxShield; playerCoins -= upgrade.cost; playerMetal -= upgrade.metalCost || 0; } else if (upgrade.name === 'damage' && playerEnergy >= (upgrade.energyCost || 0)) { ship.damage += 5; playerCoins -= upgrade.cost; playerEnergy -= upgrade.energyCost || 0; } else if (upgrade.name === 'speed' && playerEnergy >= (upgrade.energyCost || 0)) { ship.speed += 1; playerCoins -= upgrade.cost; playerEnergy -= upgrade.energyCost || 0; } if (LK.getSound('upgrade')) { LK.getSound('upgrade').play(); } updateUI(); saveProgress(); station.destroy(); upgradeStations.splice(i, 1); } if (dist > 3000) { station.destroy(); upgradeStations.splice(i, 1); } } // Update boost particles for (var i = boostParticles.length - 1; i >= 0; i--) { var particle = boostParticles[i]; particle.x += particle.vx; particle.y += particle.vy; particle.life--; particle.alpha = particle.life / 20; if (particle.life <= 0) { particle.destroy(); boostParticles.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)) { if (resources[i].type === 'metal') { playerMetal += resources[i].amount; } else { playerEnergy += 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); } } // Update pirate bases for (var i = pirateBases.length - 1; i >= 0; i--) { var base = pirateBases[i]; if (base.update) base.update(); var dist = Math.sqrt(Math.pow(base.x - ship.x, 2) + Math.pow(base.y - ship.y, 2)); // Remove base if too far or destroyed if (dist > 3500 || base._destroyed) { if (base._healthBar && base._healthBar.parent) base._healthBar.parent.removeChild(base._healthBar); base.destroy(); pirateBases.splice(i, 1); } } // Update black holes for (var i = blackHoles.length - 1; i >= 0; i--) { var bh = blackHoles[i]; if (bh.update) bh.update(); var dist = Math.sqrt(Math.pow(bh.x - ship.x, 2) + Math.pow(bh.y - ship.y, 2)); if (dist > 3000) { bh.destroy(); blackHoles.splice(i, 1); } } // Update wormholes for (var i = wormholes.length - 1; i >= 0; i--) { var wh = wormholes[i]; if (wh.update) wh.update(); var dist = Math.sqrt(Math.pow(wh.x - ship.x, 2) + Math.pow(wh.y - ship.y, 2)); if (dist > 3000) { wh.destroy(); wormholes.splice(i, 1); } } // Update trade stations (RPG/ticaret) var tradeActive = false; for (var i = tradeStations.length - 1; i >= 0; i--) { var ts = tradeStations[i]; if (ts.update) ts.update(); var dist = Math.sqrt(Math.pow(ts.x - ship.x, 2) + Math.pow(ts.y - ship.y, 2)); if (dist < 180) { tradeActive = true; // Show trade offer if (ts.specialOffer && ts.specialUpgrade) { tradeText.setText('Special: ' + ts.specialUpgrade.label + ' for ' + ts.specialUpgrade.cost + ' coins\n(Tap to buy)'); // Buy special upgrade on tap if (game._lastTradeStation !== ts && game._lastTradeStationTap !== undefined && game._lastTradeStationTap + 30 > LK.ticks) { if (playerCoins >= ts.specialUpgrade.cost) { playerCoins -= ts.specialUpgrade.cost; if (ts.specialUpgrade.name === 'maxHealth') { ship.maxHealth += 30; ship.health = ship.maxHealth; } else if (ts.specialUpgrade.name === 'maxShield') { ship.maxShield += 20; ship.shield = ship.maxShield; } else if (ts.specialUpgrade.name === 'damage') { ship.damage += 5; } else if (ts.specialUpgrade.name === 'speed') { ship.speed += 1; } LK.effects.flashObject(ship, 0x00ff99, 400); updateUI(); saveProgress(); ts.destroy(); tradeStations.splice(i, 1); tradeText.setText('Upgrade purchased!'); game._lastTradeStation = null; break; } else { tradeText.setText('Not enough coins!'); } } } else if (ts.offerType === 'buy') { tradeText.setText('Trade: Sell ' + ts.amount + ' ' + ts.resourceType + ' for ' + ts.price + ' coins\n(Tap to sell)'); // Sell resource on tap if (game._lastTradeStation !== ts && game._lastTradeStationTap !== undefined && game._lastTradeStationTap + 30 > LK.ticks) { if (ts.resourceType === 'metal' && playerMetal >= ts.amount) { playerMetal -= ts.amount; playerCoins += ts.price; LK.effects.flashObject(ship, 0x00ff99, 200); updateUI(); saveProgress(); ts.destroy(); tradeStations.splice(i, 1); tradeText.setText('Sold!'); game._lastTradeStation = null; break; } else if (ts.resourceType === 'energy' && playerEnergy >= ts.amount) { playerEnergy -= ts.amount; playerCoins += ts.price; LK.effects.flashObject(ship, 0x00ff99, 200); updateUI(); saveProgress(); ts.destroy(); tradeStations.splice(i, 1); tradeText.setText('Sold!'); game._lastTradeStation = null; break; } else { tradeText.setText('Not enough ' + ts.resourceType + '!'); } } } else if (ts.offerType === 'sell') { tradeText.setText('Trade: Buy ' + ts.amount + ' ' + ts.resourceType + ' for ' + ts.price + ' coins\n(Tap to buy)'); // Buy resource on tap if (game._lastTradeStation !== ts && game._lastTradeStationTap !== undefined && game._lastTradeStationTap + 30 > LK.ticks) { if (playerCoins >= ts.price) { playerCoins -= ts.price; if (ts.resourceType === 'metal') { playerMetal += ts.amount; } else { playerEnergy += ts.amount; } LK.effects.flashObject(ship, 0x00ff99, 200); updateUI(); saveProgress(); ts.destroy(); tradeStations.splice(i, 1); tradeText.setText('Purchased!'); game._lastTradeStation = null; break; } else { tradeText.setText('Not enough coins!'); } } } game._lastTradeStation = ts; } if (dist > 2500) { ts.destroy(); tradeStations.splice(i, 1); } } if (!tradeActive) { tradeText.setText(''); game._lastTradeStation = null; } // Spawn entities (reduced by 70%) if (LK.ticks % 100 === 0) { if (Math.random() < 0.5) { // 50% chance spawnStar(); } } // --- Anomaly Events: Space Storm, Nebula, Time Warp --- // Only one anomaly at a time, random chance every 9000 ticks if (!window.activeAnomaly && LK.ticks % 9000 === 0 && Math.random() < 0.33) { var anomalyType = Math.random(); if (anomalyType < 0.34) { // Space Storm: disables boost and slows ship for 20 seconds window.activeAnomaly = "storm"; window.anomalyExpire = LK.ticks + 1200; ship.speed = Math.max(2, ship.speed - 2); ship.boostCooldown = 9999; var anomalyFontSize = Math.round(unifiedFontSize * 1.1); var stormLabel = new Text2("UZAY FIRTINASI! Hız ve boost devre dışı!", { size: anomalyFontSize, fill: 0x00ffff, align: "center" }); stormLabel.anchor.set(0.5, 0.5); stormLabel.x = ship.x; stormLabel.y = ship.y - 200; game.addChild(stormLabel); window.anomalyLabel = stormLabel; } else if (anomalyType < 0.67) { // Nebula: disables auto-fire and reduces vision (star alpha) window.activeAnomaly = "nebula"; window.anomalyExpire = LK.ticks + 1200; window._oldStarAlpha = []; for (var i = 0; i < stars.length; i++) { window._oldStarAlpha[i] = stars[i].children[0].alpha; stars[i].children[0].alpha = 0.1; } window._oldAutoFire = ship.autoFireDisabled; ship.autoFireDisabled = true; var nebulaLabel = new Text2("NEBULA! Otomatik ateş ve görüş kısıtlı!", { size: anomalyFontSize, fill: 0xcc99ff, align: "center" }); nebulaLabel.anchor.set(0.5, 0.5); nebulaLabel.x = ship.x; nebulaLabel.y = ship.y - 200; game.addChild(nebulaLabel); window.anomalyLabel = nebulaLabel; } else { // Time Warp: all pirates/asteroids move double speed, player gets double EXP window.activeAnomaly = "timewarp"; window.anomalyExpire = LK.ticks + 1200; for (var i = 0; i < pirates.length; i++) pirates[i].speed *= 2; for (var i = 0; i < asteroids.length; i++) asteroids[i].vx *= 2, asteroids[i].vy *= 2; window._expMultiplier = 2; var warpLabel = new Text2("ZAMAN YAMULMASI! Düşmanlar hızlı, EXP x2!", { size: anomalyFontSize, fill: 0xffcc00, align: "center" }); warpLabel.anchor.set(0.5, 0.5); warpLabel.x = ship.x; warpLabel.y = ship.y - 200; game.addChild(warpLabel); window.anomalyLabel = warpLabel; } } // Anomaly expire logic if (window.activeAnomaly && LK.ticks > window.anomalyExpire) { if (window.activeAnomaly === "storm") { ship.speed = Math.min(ship.speed + 2, 10); ship.boostCooldown = 0; } else if (window.activeAnomaly === "nebula") { for (var i = 0; i < stars.length; i++) { if (window._oldStarAlpha && window._oldStarAlpha[i] !== undefined) stars[i].children[0].alpha = window._oldStarAlpha[i]; } ship.autoFireDisabled = window._oldAutoFire || false; } else if (window.activeAnomaly === "timewarp") { for (var i = 0; i < pirates.length; i++) pirates[i].speed /= 2; for (var i = 0; i < asteroids.length; i++) asteroids[i].vx /= 2, asteroids[i].vy /= 2; window._expMultiplier = 1; } if (window.anomalyLabel && window.anomalyLabel.parent) window.anomalyLabel.parent.removeChild(window.anomalyLabel); window.activeAnomaly = null; window.anomalyExpire = null; window.anomalyLabel = null; } // Spawn black holes occasionally if (LK.ticks % 3600 === 0 && Math.random() < 0.6) { spawnBlackHole(); } // Spawn wormholes occasionally if (LK.ticks % 4200 === 0 && Math.random() < 0.6) { spawnWormhole(); } // Spawn trade stations occasionally (RPG/ticaret) if (LK.ticks % 4800 === 0 && Math.random() < 0.6) { spawnTradeStation(); } // Spawn pirate bases occasionally if (LK.ticks % 6000 === 0 && Math.random() < 0.5 && pirateBases.length < 3) { spawnPirateBase(); } if (LK.ticks % 900 === 0) { var spawnRoll = Math.random(); if (spawnRoll < 0.15) { // 15% chance (pirates reduced by 85%) spawnPirate(); } else if (spawnRoll < 0.31) { // 16% chance (NPCs increased by 10%) spawnNPC(); } else if (spawnRoll < 0.33) { // 2% chance // Spawn multiple entities occasionally spawnPirate(); spawnNPC(); } } // Spawn asteroids (reduced by 70%) if (LK.ticks % 1500 === 0) { if (Math.random() < 0.5) { // 50% chance spawnAsteroid(); } } // --- Derelict Ship Event --- // Every 12000 ticks, 20% chance, only one at a time if (!window.derelictShip && LK.ticks % 12000 === 0 && Math.random() < 0.2) { // Limit derelict ship spawn distance to max 2 minutes of travel var maxTravelTime = 120; var maxDistance = (ship && ship.speed ? ship.speed : 5) * 60 * maxTravelTime; var angle = Math.random() * Math.PI * 2; var dist = Math.random() * (maxDistance * 0.5) + 400; var dx = Math.cos(angle) * dist; var dy = Math.sin(angle) * dist; var derelict = LK.getAsset('ship', { anchorX: 0.5, anchorY: 0.5, x: ship.x + dx, y: ship.y + dy, tint: 0x888888, scaleX: 1.2, scaleY: 1.2, alpha: 0.7 }); derelict._isDerelict = true; derelict._loot = { coins: 50 + Math.floor(Math.random() * 100), metal: 5 + Math.floor(Math.random() * 10), energy: 5 + Math.floor(Math.random() * 10) }; derelict._label = new Text2("Terkedilmiş Gemi", { size: 32, fill: 0xcccccc, align: "center" }); derelict._label.anchor.set(0.5, 0); derelict._label.x = derelict.x; derelict._label.y = derelict.y + 70; game.addChild(derelict); game.addChild(derelict._label); window.derelictShip = derelict; } // Derelict ship interaction if (window.derelictShip) { 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) { // Collect loot playerCoins += d._loot.coins; playerMetal += d._loot.metal; playerEnergy += d._loot.energy; var lootLabel = new Text2("Gemi yağmalandı!\n+" + d._loot.coins + " coin, +" + d._loot.metal + " metal, +" + d._loot.energy + " enerji", { size: 36, fill: 0x00ffcc, align: "center" }); lootLabel.anchor.set(0.5, 0.5); lootLabel.x = d.x; lootLabel.y = d.y - 80; game.addChild(lootLabel); if (d.parent) d.parent.removeChild(d); if (d._label && d._label.parent) d._label.parent.removeChild(d._label); window.derelictShip = null; updateUI(); saveProgress(); // Remove loot label after 2 seconds (function (lbl) { var expire = LK.ticks + 120; var removeLootLabel = function removeLootLabel() { if (LK.ticks > expire && lbl.parent) { lbl.parent.removeChild(lbl); game.update = origUpdate; } }; var origUpdate = game.update; game.update = function () { removeLootLabel(); if (origUpdate) origUpdate.apply(game, arguments); }; })(lootLabel); } else if (dist > 3000) { if (d.parent) d.parent.removeChild(d); if (d._label && d._label.parent) d._label.parent.removeChild(d._label); window.derelictShip = null; } else { // Keep label above derelict if (d._label) { d._label.x = d.x; d._label.y = d.y + 70; } } } // Wave-based pirate spawning if (LK.ticks % (180 - Math.min(waveNumber * 10, 100)) === 0) { var piratesInWave = 1 + Math.floor(waveNumber / 2); for (var j = 0; j < piratesInWave; j++) { spawnPirate(); } } // --- Distress Signal Event --- // Every 15000 ticks, 15% chance, only one at a time if (!window.distressEvent && LK.ticks % 15000 === 0 && Math.random() < 0.15) { // Limit distress event spawn distance to max 2 minutes of travel var maxTravelTime = 120; var maxDistance = (ship && ship.speed ? ship.speed : 5) * 60 * maxTravelTime; var angle = Math.random() * Math.PI * 2; var dist = Math.random() * (maxDistance * 0.5) + 400; var sx = ship.x + Math.cos(angle) * dist; var sy = ship.y + Math.sin(angle) * dist; var signal = LK.getAsset('star', { anchorX: 0.5, anchorY: 0.5, x: sx, y: sy, tint: 0xff00ff, scaleX: 4, scaleY: 4, alpha: 0.8 }); var label = new Text2("İmdat Sinyali", { size: 36, fill: 0xff00ff, align: "center" }); label.anchor.set(0.5, 0); label.x = sx; label.y = sy + 70; game.addChild(signal); game.addChild(label); window.distressEvent = { signal: signal, label: label, x: sx, y: sy, state: "waiting" }; } // Distress event logic if (window.distressEvent) { var e = window.distressEvent; var dist = Math.sqrt(Math.pow(e.x - ship.x, 2) + Math.pow(e.y - ship.y, 2)); if (e.state === "waiting" && dist < 120) { // Show choice: rescue or ignore (ambush possibility) if (!e.panel) { var panel = LK.getAsset('resource', { anchorX: 0.5, anchorY: 0.5, x: e.x, y: e.y - 180, scaleX: 7, scaleY: 2, tint: 0x222244 }); var text = new Text2("İmdat sinyali! Yardım et veya uzaklaş?", { size: 38, fill: 0xffffff, align: "center" }); text.anchor.set(0.5, 0.5); text.x = e.x; text.y = e.y - 200; var helpBtn = new Text2("Yardım Et", { size: 44, fill: 0x00ff99, align: "center" }); helpBtn.anchor.set(0.5, 0.5); helpBtn.x = e.x - 100; helpBtn.y = e.y - 120; var ignoreBtn = new Text2("Uzaklaş", { size: 44, fill: 0xff4444, align: "center" }); ignoreBtn.anchor.set(0.5, 0.5); ignoreBtn.x = e.x + 100; ignoreBtn.y = e.y - 120; game.addChild(panel); game.addChild(text); game.addChild(helpBtn); game.addChild(ignoreBtn); e.panel = panel; e.text = text; e.helpBtn = helpBtn; e.ignoreBtn = ignoreBtn; helpBtn._isDistressHelp = true; ignoreBtn._isDistressIgnore = true; helpBtn._distressEvent = e; ignoreBtn._distressEvent = e; } // Tap logic for help/ignore if (game._lastDistressTap !== e && game._lastDistressTapTick !== undefined && game._lastDistressTapTick + 30 > LK.ticks) { var tapX = game._lastDistressTapX, tapY = game._lastDistressTapY; if (tapX > e.helpBtn.x - 90 && tapX < e.helpBtn.x + 90 && tapY > e.helpBtn.y - 40 && tapY < e.helpBtn.y + 40) { // Help: 70% chance for reward, 30% ambush if (Math.random() < 0.7) { var reward = 100 + Math.floor(Math.random() * 100); playerCoins += reward; var msg = new Text2("Kurtarılan gemi! Ödül: " + reward + " coin", { size: 36, fill: 0x00ffcc, align: "center" }); msg.anchor.set(0.5, 0.5); msg.x = e.x; msg.y = e.y - 80; game.addChild(msg); updateUI(); saveProgress(); } else { // Ambush: spawn 3 pirates for (var i = 0; i < 3; i++) { var pirate = new Pirate(); pirate.x = e.x + (Math.random() - 0.5) * 100; pirate.y = e.y + (Math.random() - 0.5) * 100; pirates.push(pirate); game.addChild(pirate); } var msg = new Text2("Pusu! Korsanlar saldırıyor!", { size: 36, fill: 0xff4444, align: "center" }); msg.anchor.set(0.5, 0.5); msg.x = e.x; msg.y = e.y - 80; game.addChild(msg); } // Clean up if (e.signal && e.signal.parent) e.signal.parent.removeChild(e.signal); if (e.label && e.label.parent) e.label.parent.removeChild(e.label); if (e.panel && e.panel.parent) e.panel.parent.removeChild(e.panel); if (e.text && e.text.parent) e.text.parent.removeChild(e.text); if (e.helpBtn && e.helpBtn.parent) e.helpBtn.parent.removeChild(e.helpBtn); if (e.ignoreBtn && e.ignoreBtn.parent) e.ignoreBtn.parent.removeChild(e.ignoreBtn); window.distressEvent = null; } else if (tapX > e.ignoreBtn.x - 90 && tapX < e.ignoreBtn.x + 90 && tapY > e.ignoreBtn.y - 40 && tapY < e.ignoreBtn.y + 40) { // Ignore: nothing happens, clean up if (e.signal && e.signal.parent) e.signal.parent.removeChild(e.signal); if (e.label && e.label.parent) e.label.parent.removeChild(e.label); if (e.panel && e.panel.parent) e.panel.parent.removeChild(e.panel); if (e.text && e.text.parent) e.text.parent.removeChild(e.text); if (e.helpBtn && e.helpBtn.parent) e.helpBtn.parent.removeChild(e.helpBtn); if (e.ignoreBtn && e.ignoreBtn.parent) e.ignoreBtn.parent.removeChild(e.ignoreBtn); window.distressEvent = null; } game._lastDistressTap = e; } } else if (dist > 3000) { if (e.signal && e.signal.parent) e.signal.parent.removeChild(e.signal); if (e.label && e.label.parent) e.label.parent.removeChild(e.label); if (e.panel && e.panel.parent) e.panel.parent.removeChild(e.panel); if (e.text && e.text.parent) e.text.parent.removeChild(e.text); if (e.helpBtn && e.helpBtn.parent) e.helpBtn.parent.removeChild(e.helpBtn); if (e.ignoreBtn && e.ignoreBtn.parent) e.ignoreBtn.parent.removeChild(e.ignoreBtn); window.distressEvent = null; } else { // Keep label above signal if (e.label) { e.label.x = e.x; e.label.y = e.y + 70; } } } // Boss wave every 5 waves if (waveNumber > 0 && waveNumber % 5 === 0 && pirates.length === 0) { var bossPirate = new Pirate(); bossPirate.x = ship.x + 1000; bossPirate.y = ship.y; // Level range: wave 1 => 1-3, wave 2 => 3-5, wave 3 => 5-7, etc. var minLevel = 1 + waveNumber * 2; var maxLevel = minLevel + 2; bossPirate.level = minLevel + Math.floor(Math.random() * (maxLevel - minLevel + 1)); bossPirate.health = 200 + (bossPirate.level - 1) * 20; bossPirate.damage = 10 + Math.floor(bossPirate.level * 1.5); bossPirate.defense = 2 + Math.floor(bossPirate.level * 1.2); bossPirate.loot = 200 + bossPirate.level * 50; bossPirate.speed = 3; var bossGraphics = bossPirate.children[0]; bossGraphics.tint = 0xff00ff; bossGraphics.scaleX = 2; bossGraphics.scaleY = 2; pirates.push(bossPirate); game.addChild(bossPirate); } // 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) { var repairCostCoins = Math.max(30, Math.round((ship.maxHealth - ship.health) * 1.5)); var repairCostMetal = Math.max(2, Math.round((ship.maxHealth - ship.health) / 20)); var repairCostEnergy = Math.max(2, Math.round((ship.maxHealth - ship.health) / 25)); // Panel background var panel = LK.getAsset('resource', { anchorX: 0.5, anchorY: 0.5, x: ship.x, y: ship.y - 220, scaleX: 7, scaleY: 2, 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 } 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; } // 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; } } };
===================================================================
--- original.js
+++ change.js
@@ -546,11 +546,21 @@
availablePirates.push(pirates[i]);
}
}
}
- // Hedef korsanları seç ve işaretle
+ // Hedef korsanları seç
for (var i = 0; i < self._huntTargetCount; i++) {
var p = availablePirates[i % availablePirates.length];
+ // Limit pirate spawn distance to max 2 minutes of travel
+ var maxTravelTime = 120;
+ var maxDistance = (ship && ship.speed ? ship.speed : 5) * 60 * maxTravelTime;
+ var distToNPC = Math.sqrt(Math.pow(p.x - self.x, 2) + Math.pow(p.y - self.y, 2));
+ if (distToNPC > maxDistance) {
+ // Move pirate closer to NPC
+ var angle = Math.atan2(p.y - self.x, p.x - self.x);
+ p.x = self.x + Math.cos(angle) * (Math.random() * (maxDistance * 0.5) + 400);
+ p.y = self.y + Math.sin(angle) * (Math.random() * (maxDistance * 0.5) + 400);
+ }
self._huntTargetList.push(p);
}
self.questTarget = self._huntTargetList[0];
self._huntCurrentTargetIndex = 0;
@@ -699,11 +709,16 @@
if (self.questType === 'delivery') {
if (self.questProgress === 0) {
// Assign delivery quest: go to a random point
if (!self.questTarget) {
+ // Limit quest target distance to max 2 minutes of travel (approx 60*ship.speed*2 px)
+ var maxTravelTime = 120; // seconds
+ var maxDistance = (ship && ship.speed ? ship.speed : 5) * 60 * maxTravelTime; // px
+ var angle = Math.random() * Math.PI * 2;
+ var dist = Math.random() * (maxDistance * 0.5) + 400; // 400px min, up to maxDistance/2
self.questTarget = {
- x: self.x + (Math.random() - 0.5) * 2000,
- y: self.y + (Math.random() - 0.5) * 2000
+ x: self.x + Math.cos(angle) * dist,
+ y: self.y + Math.sin(angle) * dist
};
return self.rpgName + ": Can you deliver this package to (" + Math.floor(self.questTarget.x) + "," + Math.floor(self.questTarget.y) + ")?";
} else {
var dx = ship.x - self.questTarget.x;
@@ -725,11 +740,16 @@
}
if (self.questType === 'explore') {
if (self.questProgress === 0) {
if (!self.questTarget) {
+ // Limit quest target distance to max 2 minutes of travel
+ var maxTravelTime = 120;
+ var maxDistance = (ship && ship.speed ? ship.speed : 5) * 60 * maxTravelTime;
+ var angle = Math.random() * Math.PI * 2;
+ var dist = Math.random() * (maxDistance * 0.5) + 400;
self.questTarget = {
- x: self.x + (Math.random() - 0.5) * 2000,
- y: self.y + (Math.random() - 0.5) * 2000
+ x: self.x + Math.cos(angle) * dist,
+ y: self.y + Math.sin(angle) * dist
};
return self.rpgName + ": Can you explore the area at (" + Math.floor(self.questTarget.x) + "," + Math.floor(self.questTarget.y) + ")?";
} else {
var dx = ship.x - self.questTarget.x;
@@ -751,11 +771,16 @@
}
if (self.questType === 'escort') {
if (self.questProgress === 0) {
if (!self.questTarget) {
+ // Limit quest target distance to max 2 minutes of travel
+ var maxTravelTime = 120;
+ var maxDistance = (ship && ship.speed ? ship.speed : 5) * 60 * maxTravelTime;
+ var angle = Math.random() * Math.PI * 2;
+ var dist = Math.random() * (maxDistance * 0.5) + 400;
self.questTarget = {
- x: self.x + (Math.random() - 0.5) * 2000,
- y: self.y + (Math.random() - 0.5) * 2000
+ x: self.x + Math.cos(angle) * dist,
+ y: self.y + Math.sin(angle) * dist
};
return self.rpgName + ": Can you escort me to (" + Math.floor(self.questTarget.x) + "," + Math.floor(self.questTarget.y) + ")?";
} else {
var dx = self.x - self.questTarget.x;
@@ -3522,13 +3547,20 @@
}
// --- Derelict Ship Event ---
// Every 12000 ticks, 20% chance, only one at a time
if (!window.derelictShip && LK.ticks % 12000 === 0 && Math.random() < 0.2) {
+ // Limit derelict ship spawn distance to max 2 minutes of travel
+ var maxTravelTime = 120;
+ var maxDistance = (ship && ship.speed ? ship.speed : 5) * 60 * maxTravelTime;
+ var angle = Math.random() * Math.PI * 2;
+ var dist = Math.random() * (maxDistance * 0.5) + 400;
+ var dx = Math.cos(angle) * dist;
+ var dy = Math.sin(angle) * dist;
var derelict = LK.getAsset('ship', {
anchorX: 0.5,
anchorY: 0.5,
- x: ship.x + (Math.random() - 0.5) * 2000,
- y: ship.y + (Math.random() - 0.5) * 2000,
+ x: ship.x + dx,
+ y: ship.y + dy,
tint: 0x888888,
scaleX: 1.2,
scaleY: 1.2,
alpha: 0.7
@@ -3610,10 +3642,15 @@
}
// --- Distress Signal Event ---
// Every 15000 ticks, 15% chance, only one at a time
if (!window.distressEvent && LK.ticks % 15000 === 0 && Math.random() < 0.15) {
- var sx = ship.x + (Math.random() - 0.5) * 2500;
- var sy = ship.y + (Math.random() - 0.5) * 2500;
+ // Limit distress event spawn distance to max 2 minutes of travel
+ var maxTravelTime = 120;
+ var maxDistance = (ship && ship.speed ? ship.speed : 5) * 60 * maxTravelTime;
+ var angle = Math.random() * Math.PI * 2;
+ var dist = Math.random() * (maxDistance * 0.5) + 400;
+ var sx = ship.x + Math.cos(angle) * dist;
+ var sy = ship.y + Math.sin(angle) * dist;
var signal = LK.getAsset('star', {
anchorX: 0.5,
anchorY: 0.5,
x: sx,
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