User prompt
Kod içinde olan veya olmayan, oyuna uygun birçok özelliği veya mekaniği aktif et. Uyumsuz ise ekleme. Birbirinden farklı, eğlence katacak ve çeşitlilik katacak ayrıca otomasyon hale gelecek AdventureRPG katacak mekanik ve özellik ekle.
User prompt
Korsan altında bulunan ''savunma seviye'' yazısı kaldır
User prompt
Escort görevinde NPC hedef koordinata gitsin, biz yanında gidelim.
User prompt
Korsanın saldırı ve savunma gücünü, bulunduğu seviyesine oranla yükselt.
User prompt
Wave 1 iken 1-3 seviye, wave 2 iken 3-5 seviye... diye orantılı şekilde yükselsin.
User prompt
Her Wave yükseldiğinde korsan gemilerinin seviyeleri yükselsin. Seviyesi yükselen korsan gemilerinin canı ve saldırı gücü artsın. Ayrıca Seviyesi gemilerinin alt kısmında küçük yazı ile yazsın.
User prompt
Koordinat, Anlık olarak bulunduğumuz konumun koordinatını yazsın. Mesela NPC'den görev alıyorum ama koordinat bilmediğim için yapamıyorum.
User prompt
Ekranın sağ alt köşesine ''Reset'' butonu ekle ve bütün ilerleme tamamen sıfırlanmasını sağla. Yazı fontu Heath yazı fontu gibi olsun.
User prompt
Her korsan öldürdüğümüzde, 1-3 arasında Exp versin.
User prompt
Koordinat'ı Wave'nin sol yanına kaydır
User prompt
Seviye, Rep boyutlarını da aynı yap
User prompt
Üst kısımda bulunan yazıların tamamının font boyutunu, Koordinat yazı font boyutu ile aynı olsun.
User prompt
Kordinatı %25 oranında sola kaydır
User prompt
Kordinatı %20 oranında sola kaydır
User prompt
kordinatı %30 oranında küçült.
User prompt
Kordinatı, Level yazısının üzerine gelecek şekilde kaydır. Ayrıca %10 oranında büyüt ve güncel konumu anlık olarak göstersin.
User prompt
eklediğin kordinatı sağa kaydır ve %50 oranında küçült. Ayrıca anlık olarak göstersin.
User prompt
Wave sol yanına, küçük şekilde haritada bulunduğumuz kordinat yazsın.
User prompt
Korsan Base'leri olsun bazı yerlerde, Korsan Base etrafında birçok korsan olsun ve bu base anlık; 10 korsan saldırı ve savunma gücüne sahip olsun. (Takılma, takılınca yeniden başlat)
User prompt
Saldırı Mesafesini %10 arttır.
User prompt
Saldırı alabilen veya saldırı yapabilen herşeyin can barı olsun.
User prompt
Avcılık görevinde, Kabul edildiği zaman görevi NPC yönetsin. Belli bir süre veya korsan sayısı belirtilsin görevde.
User prompt
Yada birden fazla korsanın, NPC'ye saldıracağı ve NPC yardım isteğinde bulunması konusunda sistem ekle. Kabul edersek, korsanlardan NPC'yi koruyalım ve korsanları öldürünce NPC ödül versin. Kabul etmez isek, NPC'ye ilgili korsanlar saldırsın ve yok etsin. Böylece iyi ve kötü rep kazanalım. NPC'ler ona göre bize ödüller versinler.
User prompt
Bu tarz görevlerin, gerçekleşmesi için npc durumu yönetsin. Korsan saldırı görevleri de olsun. NPC ile saldıralım birlikte saldıralım felan.
User prompt
Escort görevini yapacağım ama npc sabit yerde duruyor.
/****
* 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) {
// Eğer oyuncu NPC'ye yakınsa, NPC hedefe doğru hareket etmeye başlasın
var playerDist = Math.sqrt(Math.pow(ship.x - self.x, 2) + Math.pow(ship.y - self.y, 2));
if (playerDist < 220 && self.questProgress === 0) {
// 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);
}
}
// 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;
}
}
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ç ve işaretle
for (var i = 0; i < self._huntTargetCount; i++) {
var p = availablePirates[i % availablePirates.length];
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);
if (dist > 120) {
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
var playerDist = Math.sqrt(Math.pow(ship.x - self.questTarget.x, 2) + Math.pow(ship.y - self.questTarget.y, 2));
if (playerDist < 200 && dist < 200) {
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) {
self.questTarget = {
x: self.x + (Math.random() - 0.5) * 2000,
y: self.y + (Math.random() - 0.5) * 2000
};
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) {
self.questTarget = {
x: self.x + (Math.random() - 0.5) * 2000,
y: self.y + (Math.random() - 0.5) * 2000
};
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) {
self.questTarget = {
x: self.x + (Math.random() - 0.5) * 2000,
y: self.y + (Math.random() - 0.5) * 2000
};
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
if (pirates.length > 0) {
self.questTarget = pirates[Math.floor(Math.random() * pirates.length)];
return self.rpgName + ": Can you defeat pirate #" + self.questTarget.rpgName + "?";
} else {
return self.rpgName + ": No pirates nearby, come back later!";
}
} else {
if (self.questTarget._destroyed) {
self.questProgress = 1;
playerCoins += self.reward;
questsCompleted++;
var expMsg = gainEXP(50 + Math.floor(Math.random() * 20));
return self.rpgName + ": Pirate defeated! Reward: " + self.reward + " coins!" + (expMsg ? "\n" + expMsg : "");
} else {
return self.rpgName + ": Please defeat pirate #" + (self.questTarget.rpgName || "unknown");
}
}
} else {
return self.rpgName + ": You are a true hero!";
}
}
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
});
self.health = 30;
self.speed = 2;
self.fireRate = 60;
self.lastFire = 0;
self.loot = Math.floor(Math.random() * 30) + 10;
self.moveAngle = Math.random() * Math.PI * 2;
self.patrolTimer = 0;
self.aggroRange = 600;
self.takeDamage = function (amount) {
self.health -= amount;
LK.effects.flashObject(self, 0xffffff, 100);
};
self.update = function () {
// 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;
});
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 tradeText = new Text2('', {
size: 40,
fill: 0x00ff99
});
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;
pirate.health = 30 + waveNumber * 10;
pirate.damage = 5 + Math.floor(waveNumber / 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
var coinText = new Text2('Coins: ' + playerCoins, {
size: 50,
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: 40,
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: 50,
fill: 0x00FF00
});
healthText.anchor.set(0.5, 0);
LK.gui.top.addChild(healthText);
var shieldText = new Text2('Shield: 50/50', {
size: 40,
fill: 0x0088FF
});
shieldText.anchor.set(0.5, 0);
shieldText.y = 60;
LK.gui.top.addChild(shieldText);
var boostText = new Text2('BOOST READY', {
size: 35,
fill: 0x00FFFF
});
boostText.anchor.set(0.5, 0);
boostText.y = 110;
LK.gui.top.addChild(boostText);
var waveText = new Text2('Wave: 1', {
size: 45,
fill: 0xFFFFFF
});
waveText.anchor.set(1, 0);
waveText.x = -20;
waveText.y = 20;
LK.gui.topRight.addChild(waveText);
// 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: 38,
fill: 0x00ffcc
});
expText.anchor.set(1, 0);
expText.x = -20;
expText.y = 80;
LK.gui.topRight.addChild(expText);
// 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;
}
// Scale pirate stats based on wave
pirate.health = 30 + waveNumber * 10;
pirate.damage = 5 + Math.floor(waveNumber / 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: 36,
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) {
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) {
// Boost when tapping upper area of screen
ship.boostSpeed = 10;
ship.boostCooldown = 300; // 5 seconds cooldown
if (LK.getSound('boost')) {
LK.getSound('boost').play();
}
} else {
// --- 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;
}
}
}
};
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
if (LK.ticks - ship.lastFire > ship.fireRate && (pirates.length > 0 || asteroids.length > 0)) {
// Find nearest pirate or asteroid within 200 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 < 200 && 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 < 200 && 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);
}
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 200 pixels)
if (!huntedByNPC && dist < 200) {
// 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);
}
}
// 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 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();
}
}
// 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();
}
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();
}
}
// 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();
}
}
// 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;
bossPirate.health = 200 + waveNumber * 20;
bossPirate.damage = 10 + waveNumber;
bossPirate.loot = 200 + waveNumber * 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();
}; ===================================================================
--- original.js
+++ change.js
@@ -156,8 +156,67 @@
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,
@@ -1214,8 +1273,25 @@
// 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++) {
@@ -1277,8 +1353,25 @@
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() {
@@ -1309,8 +1402,25 @@
}
// Scale pirate stats based on wave
pirate.health = 30 + waveNumber * 10;
pirate.damage = 5 + Math.floor(waveNumber / 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() {
@@ -1333,8 +1443,25 @@
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() {
@@ -1901,8 +2028,9 @@
}
// 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;
@@ -1967,8 +2095,9 @@
// 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();
@@ -2251,8 +2380,9 @@
}
// 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);
@@ -2545,6 +2675,7 @@
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();
};
\ No newline at end of file
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