User prompt
zindanlardaki level barı ve textini overworldde sol altta gözükecek şekilde ekle
User prompt
enemytank assetli düşmanların y kordinatını 200 birim aşağıda gözükecek şekilde değiş
User prompt
enemyarcher assetli düşmanların y kordinatını 100 birim aşağıda gözükecek şekilde değiş
User prompt
enemyfast assetli düşmanların y kordinatını 130 birim yukarda gözükücek şekilde değiştir
User prompt
ch23 assetli canavarlar overworldde daha sık ortaya çıksın
User prompt
bazen overworlde öldürülen ch23 assetli her canavar can değerini 1 birim yenilemiyor bu sorunu düzelt her öldürülen ch23 assetli canavar 1 birim can yenilesin
User prompt
overworldde karakterimizin taktığı itemlerinin ne kadar health bonus, damage bonus ,defense bonusu verdiğini görebileceğimiz bir statların gözüktüğü bir yer ekle sağ alt köşeye
User prompt
In the current combat system, when the player dies inside a dungeon, the game shows a Game Over screen and restarts the game. I want to disable the full restart on dungeon death. 🔄 Instead, if the player dies during combat, please: Set the player’s health to 1 Return to the overworld state Do not lose progress (no reset or loss of experience/items) 📍 This should replace the LK.showGameOver(); call with logic like: js Kopyala Düzenle playerCharacter.health = 1; currentState = 'overworld'; setupOverworld(); updateHealthBar(); Please apply this logic inside the part where the player’s death is handled in combat (usually inside game.update() or when checking if (playerCharacter.health <= 0)).
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'Error: Invalid value. Only literals or 1-level deep objects/arrays containing literals are allowed.' in or related to this line: 'storage.dungeonEntryOrder = gameData.dungeonEntryOrder;' Line Number: 1244 ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Orijinal kodda şöyle bir şey var: js if (draggedCharacter.intersects(dungeon)) { currentState = 'combat'; currentDungeon = dungeon; setupCombat(); break; } BUNUN YERİNE ŞUNU YAZ: js if (draggedCharacter.intersects(dungeon)) { currentState = 'combat'; currentDungeon = dungeon; // NORMAL veya HARD zindanlara girince ENTRY ORDER kaydedilsin if (dungeon.difficulty === 'normal' || dungeon.difficulty === 'hard') { var orderKey = 'map' + currentMap + '_' + dungeon.difficulty + '_order'; if (!gameData.dungeonEntryOrder[orderKey]) { gameData.dungeonEntryOrder[orderKey] = []; } if (!gameData.dungeonEntryOrder[orderKey].includes(dungeon.index)) { gameData.dungeonEntryOrder[orderKey].push(dungeon.index); } } setupCombat(); break; } Bu ekleme, normal/hard dungeon'a girdiğinde sıralama (entryOrder) kaydını garanti altına alır. Sorunun birinci sebebiydi bu. 🔧 2. Enemy.die Fonksiyonunu DÜZENLE Bul: Şöyle bir yer olacak kodda (veya benzeri): js self.die = function () { LK.getSound('enemyDeath').play(); playerCharacter.gainExperience(self.experienceReward); }; ✅ Bunun yerine ŞUNU YAZ: js self.die = function () { LK.getSound('enemyDeath').play(); playerCharacter.gainExperience(self.experienceReward); self.destroy(); // enemies[] listesinden bu düşmanı çıkar var index = enemies.indexOf(self); if (index > -1) { enemies.splice(index, 1); } // Tüm düşmanlar öldüyse overworld'e dön if (totalEnemiesSpawned >= 15 && enemies.length === 0) { completeDungeon(currentMap, currentDungeon.difficulty, currentDungeon.index); LK.setTimeout(function () { currentState = 'overworld'; setupOverworld(); }, 1000); } };
Code edit (1 edits merged)
Please save this source code
User prompt
In my dungeon combat system, even after I defeat all enemies, the game doesn't return to the overworld — it stays stuck in the dungeon. I believe the issue lies in this condition: js Kopyala Düzenle if (totalEnemiesSpawned >= 15 && enemies.length === 0) This likely never becomes true because the enemies array is not being updated correctly when an enemy dies. Please do the following: 1. Fix the Enemy.die() method: Make sure it calls self.destroy() to remove the enemy from the screen. Also make sure it removes the enemy from the enemies[] array. Example: js Kopyala Düzenle self.die = function () { LK.getSound('enemyDeath').play(); playerCharacter.gainExperience(self.experienceReward); self.destroy(); var index = enemies.indexOf(self); if (index > -1) { enemies.splice(index, 1); } if (totalEnemiesSpawned >= 15 && enemies.length === 0) { completeDungeon(currentMap, currentDungeon.difficulty, currentDungeon.index); LK.setTimeout(function () { currentState = 'overworld'; setupOverworld(); }, 1000); } }; 2. Alternatively: Move the victory condition check into the die() function instead of checking it only in game.update(), so it always runs when an enemy is eliminated. This should ensure that once all 15 enemies are killed, the game transitions correctly back to the overworld.
User prompt
overworldde öldürülen her bir ch23 assetli yaratık 1 can yenilesin ,max can değeri fullenince ya da max health doluysa yenilemesin
Code edit (1 edits merged)
Please save this source code
User prompt
overworldeki combat sistemini ana karakterin her gelen ch23 assetli düşman için otomatik olarak 1 ok atsın ve ok otomatik olarak hedefe gitsin şekilde değiştir.1000 menzil çapı olsun ana karakterin.menzile giren düşmanlara ok atabilsin
Code edit (6 edits merged)
Please save this source code
User prompt
In my dungeon combat system, I want to remove the automatic homing arrow behavior. Instead, I want to implement a classic drag-and-release archery system. The player should tap and hold on the screen to start aiming, drag to set direction and power, and when they release (finger or mouse), an arrow should be fired in that direction. The arrows should follow a realistic trajectory, based on their speed and angle of release. Please update the Arrow class accordingly: Inside Arrow.update, remove all target searching and direction adjustment logic (homing behavior). The arrow should simply move in the direction defined when released. Also, modify the game.down, game.move, and game.up functions to properly support the drag-to-aim and release-to-shoot system. ✅ Additionally, please add a visible aiming line or direction indicator while the player is dragging, to help with aiming feedback.
User prompt
I want to completely replace the current combat arrow shooting system in my dungeon gameplay. Please remove the automatic homing arrow system and implement a drag-and-release aiming mechanic, like in classic archery games. Here's what I need: 🎯 Shooting System: When the player taps and holds (game.down), the aiming starts. While holding and moving (game.move), the direction and power are defined. On release (game.up), an arrow is created and launched in that direction with speed based on the drag length. The arrow should travel in a straight line using the initial velocity (no homing, no auto-targeting). 🔧 Remove the following: In the Arrow.update function, remove all code that searches for the closest target and adjusts velocity toward enemies or monsters. Specifically remove all blocks like: js Kopyala Düzenle var closestTarget = null; var closestDistance = Infinity; ... self.velocityX = dx / distance * self.speed; self.velocityY = dy / distance * self.speed; and the rotation logic that orients the arrow to the target. Remove or disable the entire energy system: Do not check for currentEnergy before shooting. Remove or comment out all energy-related variables like currentEnergy, energyRegenTimer, wasEnergyDepleted, and updateEnergyBar() calls. Shooting should be allowed without restriction. ✅ Update: Update the Arrow class to simply move using: js Kopyala Düzenle self.x += self.velocityX; self.y += self.velocityY; Modify game.down, game.move, and game.up functions to support the drag-to-aim-and-release system. 🔍 Optional: Add a visual aiming line or arrow direction indicator while dragging if helpful. The energy bar UI can stay for visual purposes but must have no functional restriction on shooting. The goal is to give the player full manual aiming control and a more skill-based archery system. Please implement accordingly.
Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
User prompt
karakterin 50 birim üstüne yeşil health bar ekle ve barın üstünde can miktarı yazsın
User prompt
eğer bir zindan sonunda eşya kazanılıyorsa kazanılan eşyanın bildirimi zindan geçildikten sonra overworldde bildirim olarak yazsın
Code edit (1 edits merged)
Please save this source code
User prompt
her yüzük derecesinden sadece 1 adet düşebilsin yani 1oyunda sadece 1 common yüzük,1 rare yüzük, 1 epic yüzük , 1 legandry yüzük olsun
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var Arrow = Container.expand(function () { var self = Container.call(this); var arrowGraphics = self.attachAsset('arrow', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 5; self.velocityX = 1; // Default rightward direction self.velocityY = 0; self.update = function () { // Find closest target (enemy or overworld monster) for homing behavior var closestTarget = null; var closestDistance = Infinity; // Check enemies first for (var i = 0; i < enemies.length; i++) { var enemy = enemies[i]; var dx = enemy.x - self.x; var dy = enemy.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < closestDistance) { closestDistance = distance; closestTarget = enemy; } } // Check overworld monsters for (var i = 0; i < overworldMonsters.length; i++) { var monster = overworldMonsters[i]; var dx = monster.x - self.x; var dy = monster.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < closestDistance) { closestDistance = distance; closestTarget = monster; } } // Update direction toward closest target, or continue rightward if no targets if (closestTarget && closestDistance > 10) { // Avoid jitter when very close var dx = closestTarget.x - self.x; var dy = closestTarget.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); self.velocityX = dx / distance * self.speed; self.velocityY = dy / distance * self.speed; // Rotate arrow to face direction arrowGraphics.rotation = Math.atan2(dy, dx); } else if (!closestTarget) { // No targets, travel rightward self.velocityX = self.speed; self.velocityY = 0; arrowGraphics.rotation = 0; } // Move arrow self.x += self.velocityX; self.y += self.velocityY; }; return self; }); var Character = Container.expand(function () { var self = Container.call(this); var characterGraphics = self.attachAsset('character', { anchorX: 0.5, anchorY: 0.5 }); // Character stats self.level = 1; self.experience = 0; self.health = 100; self.maxHealth = 100; self.damage = 10; self.defense = 0; // Equipment slots self.equipment = { helmet: null, boots: null, armor: null, bow: null, necklace: null, ring: null, gloves: null }; self.calculateStats = function () { self.maxHealth = 100 + self.level * 10; self.damage = 10 + self.level * 2; self.defense = 0 + self.level * 1; // Add equipment bonuses for (var slot in self.equipment) { if (self.equipment[slot]) { var item = self.equipment[slot]; self.maxHealth += item.healthBonus || 0; self.damage += item.damageBonus || 0; self.defense += item.defenseBonus || 0; } } if (self.health > self.maxHealth) { self.health = self.maxHealth; } }; self.gainExperience = function (amount) { self.experience += amount; var levelUpThreshold = self.level * 100; if (self.experience >= levelUpThreshold) { self.level++; self.experience -= levelUpThreshold; self.calculateStats(); self.health = self.maxHealth; LK.getSound('levelUp').play(); } // Update level bar if in combat if (currentState === 'combat') { updateLevelBar(); } }; return self; }); var Dungeon = Container.expand(function (difficulty, index) { var self = Container.call(this); var dungeonGraphics = self.attachAsset('dungeon', { anchorX: 0.5, anchorY: 0.5 }); self.difficulty = difficulty; self.index = index; self.isHovered = false; // Difficulty colors var colors = { easy: 0x90EE90, normal: 0xFFD700, hard: 0xFF8C00, veryHard: 0xFF4500 }; dungeonGraphics.tint = colors[difficulty]; // Add difficulty text var difficultyNames = { easy: 'EASY', normal: 'NORMAL', hard: 'HARD', veryHard: 'VERY HARD' }; var difficultyText = new Text2(difficultyNames[difficulty], { size: 50, fill: 0xFFFFFF }); difficultyText.anchor.set(0.5, 1); difficultyText.x = 0; difficultyText.y = -80; self.addChild(difficultyText); self.down = function (x, y, obj) { // Track entry order for normal and hard dungeons if (difficulty === 'normal' || difficulty === 'hard') { var orderKey = 'map' + currentMap + '_' + difficulty + '_order'; // Ensure gameData exists and is an object if (!gameData || _typeof(gameData) !== 'object') { gameData = {}; } // Ensure gameData.dungeonEntryOrder exists as an object if (!gameData.dungeonEntryOrder || _typeof(gameData.dungeonEntryOrder) !== 'object') { gameData.dungeonEntryOrder = {}; } // Ensure the specific order key exists as an array - with additional safety checks try { if (!gameData.dungeonEntryOrder[orderKey] || !Array.isArray(gameData.dungeonEntryOrder[orderKey])) { gameData.dungeonEntryOrder[orderKey] = []; } // Add this dungeon index to entry order if not already present if (gameData.dungeonEntryOrder[orderKey].indexOf(index) === -1) { gameData.dungeonEntryOrder[orderKey].push(index); } } catch (e) { // Fallback: reinitialize dungeonEntryOrder if there's any error gameData.dungeonEntryOrder = {}; gameData.dungeonEntryOrder[orderKey] = [index]; } } currentState = 'combat'; currentDungeon = self; setupCombat(); }; return self; }); var Enemy = Container.expand(function (difficulty, enemyType) { var self = Container.call(this); // Select appropriate asset based on enemy type var assetName = 'enemyBasic'; // default if (enemyType === 'basic') { assetName = 'enemyBasic'; } else if (enemyType === 'fast') { assetName = 'enemyFast'; } else if (enemyType === 'tank') { assetName = 'enemyTank'; } else if (enemyType === 'archer') { assetName = 'enemyArcher'; } else if (enemyType === 'boss') { assetName = 'enemyBoss'; } var enemyGraphics = self.attachAsset(assetName, { anchorX: 0.5, anchorY: 0.5 }); self.enemyType = enemyType || 'basic'; self.difficulty = difficulty; // Base stats for different enemy types var enemyStats = { basic: { health: 50, speed: 1.6, tint: 0xFFFFFF, experience: 10, damage: 20 }, fast: { health: 30, speed: 2.4, tint: 0x00FF00, experience: 15, damage: 20 }, tank: { health: 120, speed: 1, tint: 0xFF0000, experience: 25, damage: 30 }, archer: { health: 40, speed: 3, tint: 0x0000FF, experience: 20, damage: 50 }, boss: { health: 400, speed: 1, tint: 0xFF00FF, experience: 50, damage: 100 } }; var stats = enemyStats[self.enemyType]; var healthMultiplier = { easy: 1, normal: 2, hard: 4, veryHard: 8 }; self.maxHealth = stats.health * healthMultiplier[difficulty]; self.health = self.maxHealth; self.speed = stats.speed; self.experienceReward = stats.experience; self.damage = stats.damage; // Apply visual tint based on enemy type enemyGraphics.tint = stats.tint; self.update = function () { self.x -= self.speed; }; self.takeDamage = function (damage) { self.health -= damage; if (self.health <= 0) { self.die(); } }; self.die = function () { LK.getSound('enemyDeath').play(); playerCharacter.gainExperience(self.experienceReward); }; return self; }); var LootItem = Container.expand(function (type, rarity, x, y) { var self = Container.call(this); var lootGraphics = self.attachAsset(type, { anchorX: 0.5, anchorY: 0.5 }); self.type = type; self.rarity = rarity; // Rarity colors var rarityColors = { common: 0x808080, rare: 0x4169e1, epic: 0x8a2be2, legendary: 0xffd700 }; lootGraphics.tint = rarityColors[rarity]; // Generate random stats based on rarity var multiplier = { common: 1, rare: 2, epic: 3, legendary: 5 }; self.healthBonus = Math.floor(Math.random() * 20 * multiplier[rarity]); self.damageBonus = Math.floor(Math.random() * 10 * multiplier[rarity]); self.defenseBonus = Math.floor(Math.random() * 5 * multiplier[rarity]); self.x = x; self.y = y; self.down = function (x, y, obj) { collectLoot(self); }; return self; }); var OverworldMonster = Container.expand(function () { var self = Container.call(this); var monsterGraphics = self.attachAsset('ch23', { anchorX: 0.5, anchorY: 0.5 }); self.health = 1; self.maxHealth = 1; self.speed = 4; // Slow movement self.lastX = 0; self.lastY = 0; self.update = function () { // Track last position for collision detection self.lastX = self.x; self.lastY = self.y; // Move slowly towards player var dx = playerCharacter.x - self.x; var dy = playerCharacter.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 5) { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; } }; self.takeDamage = function (damage) { self.health -= damage; if (self.health <= 0) { self.die(); } }; self.die = function () { LK.getSound('enemyDeath').play(); playerCharacter.gainExperience(20); // Store monster position for ring drop var monsterX = self.x; var monsterY = self.y; // Ring drop chances var randomChance = Math.random(); if (randomChance < 0.0000001) { // 0.00000001 chance for legendary ring createRingDrop('legendary', monsterX, monsterY); } else if (randomChance < 0.000001) { // 0.0000001 chance for epic ring createRingDrop('epic', monsterX, monsterY); } else if (randomChance < 0.00001) { // 0.000001 chance for rare ring createRingDrop('rare', monsterX, monsterY); } else if (randomChance < 100) { // 0.00001 chance for common ring createRingDrop('common', monsterX, monsterY); } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // Sounds // UI assets // Loot assets // Combat assets // Character and world assets // Game state function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } var currentState = 'overworld'; // 'overworld', 'combat', 'inventory' var currentMap = 1; var currentDungeon = null; var playerCharacter = new Character(); var dungeons = []; var arrows = []; var enemies = []; var lootItems = []; var overworldMonsters = []; var lastEnemySpawn = 0; var lastArrowShot = 0; var lastOverworldMonsterSpawn = 0; var lastOverworldArrowShot = 0; var combatTimer = 0; var enemiesKilled = 0; var targetKills = 15; var totalEnemiesSpawned = 0; var maxEnergy = 5; var currentEnergy = 5; var energyRegenTimer = 1; var energyRegenDelay = 50; // 0.3 seconds at 60fps var isRegeneratingEnergy = false; var wasEnergyDepleted = false; var energyBar = null; var energyBarBg = null; var levelBarBg = null; var levelBarFill = null; var experienceText = null; var levelBarText = null; // UI elements var levelText = new Text2('Level: 1', { size: 40, fill: 0xFFFFFF }); var healthText = new Text2('Health: 100/100', { size: 40, fill: 0xFFFFFF }); var backButton = null; // Initialize storage with defaults var gameData = { level: storage.level || 1, experience: storage.experience || 0, equipment: { helmet: null, boots: null, armor: null, bow: null, necklace: null, ring: null, gloves: null }, unlockedMaps: storage.unlockedMaps || 1, completedDungeons: storage.completedDungeons || {}, givenLoot: storage.givenLoot || {}, dungeonEntryOrder: storage.dungeonEntryOrder || {} }; // Load equipment from storage if (storage.equipmentHelmetType) { gameData.equipment.helmet = { type: storage.equipmentHelmetType, rarity: storage.equipmentHelmetRarity, healthBonus: storage.equipmentHelmetHealthBonus, damageBonus: storage.equipmentHelmetDamageBonus, defenseBonus: storage.equipmentHelmetDefenseBonus }; } if (storage.equipmentBootsType) { gameData.equipment.boots = { type: storage.equipmentBootsType, rarity: storage.equipmentBootsRarity, healthBonus: storage.equipmentBootsHealthBonus, damageBonus: storage.equipmentBootsDamageBonus, defenseBonus: storage.equipmentBootsDefenseBonus }; } if (storage.equipmentArmorType) { gameData.equipment.armor = { type: storage.equipmentArmorType, rarity: storage.equipmentArmorRarity, healthBonus: storage.equipmentArmorHealthBonus, damageBonus: storage.equipmentArmorDamageBonus, defenseBonus: storage.equipmentArmorDefenseBonus }; } if (storage.equipmentBowType) { gameData.equipment.bow = { type: storage.equipmentBowType, rarity: storage.equipmentBowRarity, healthBonus: storage.equipmentBowHealthBonus, damageBonus: storage.equipmentBowDamageBonus, defenseBonus: storage.equipmentBowDefenseBonus }; } if (storage.equipmentNecklaceType) { gameData.equipment.necklace = { type: storage.equipmentNecklaceType, rarity: storage.equipmentNecklaceRarity, healthBonus: storage.equipmentNecklaceHealthBonus, damageBonus: storage.equipmentNecklaceDamageBonus, defenseBonus: storage.equipmentNecklaceDefenseBonus }; } if (storage.equipmentRingType) { gameData.equipment.ring = { type: storage.equipmentRingType, rarity: storage.equipmentRingRarity, healthBonus: storage.equipmentRingHealthBonus, damageBonus: storage.equipmentRingDamageBonus, defenseBonus: storage.equipmentRingDefenseBonus }; } if (storage.equipmentGlovesType) { gameData.equipment.gloves = { type: storage.equipmentGlovesType, rarity: storage.equipmentGlovesRarity, healthBonus: storage.equipmentGlovesHealthBonus, damageBonus: storage.equipmentGlovesDamageBonus, defenseBonus: storage.equipmentGlovesDefenseBonus }; } // Load saved data playerCharacter.level = gameData.level; playerCharacter.experience = gameData.experience; playerCharacter.equipment = gameData.equipment; playerCharacter.calculateStats(); // Update character appearance based on loaded equipment updateCharacterAppearance(); // Load dungeon progression gameData.completedDungeons = storage.completedDungeons || {}; gameData.givenLoot = storage.givenLoot || {}; currentMap = storage.unlockedMaps || 1; // Setup overworld function setupOverworld() { game.removeChildren(); // Add background var background = game.attachAsset('mapBackground', { anchorX: 0, anchorY: 0, x: 0, y: 0 }); // Add character at center playerCharacter.x = 1024; playerCharacter.y = 1366; game.addChild(playerCharacter); // Create dungeons in isometric grid dungeons = []; var allDifficulties = ['easy', 'easy', 'easy', 'easy', 'normal', 'normal', 'normal', 'hard', 'hard', 'veryHard']; // Function to check if position is valid (at least 300 units away from existing dungeons and 300 from player) function isValidPosition(x, y, existingDungeons) { // Check distance from player starting position (1024, 1366) var playerStartX = 1024; var playerStartY = 1366; var distanceFromPlayer = Math.sqrt(Math.pow(x - playerStartX, 2) + Math.pow(y - playerStartY, 2)); if (distanceFromPlayer < 300) { return false; } // Check distance from existing dungeons using Euclidean distance for (var i = 0; i < existingDungeons.length; i++) { var dx = x - existingDungeons[i].x; var dy = y - existingDungeons[i].y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 300) { return false; } } return true; } // Create all 10 dungeons but control their interaction based on progression var difficultyIndices = { easy: 0, normal: 0, hard: 0, veryHard: 0 }; for (var i = 0; i < allDifficulties.length; i++) { var difficulty = allDifficulties[i]; var dungeonIndex = difficultyIndices[difficulty]; var completedCount = getCompletedDungeonsForDifficulty(currentMap, difficulty); var isUnlocked = isDifficultyUnlocked(currentMap, difficulty); var isCompleted = dungeonIndex < completedCount; // Skip creating completed dungeons (they should disappear) if (isCompleted) { difficultyIndices[difficulty]++; continue; } var dungeon = new Dungeon(difficulty, dungeonIndex); difficultyIndices[difficulty]++; // Apply visual effects based on lock status if (!isUnlocked) { // Dim locked dungeons dungeon.children[0].tint = 0x666666; dungeon.children[0].alpha = 0.5; // Disable interaction for locked dungeons dungeon.down = null; } // Find valid position with minimum distance requirement var validPosition = false; var attempts = 0; while (!validPosition && attempts < 100) { var testX = 150 + Math.random() * (2048 - 300); // 150 to 1898 var testY = 400 + Math.random() * (2732 - 800); // 400 to 2332 if (isValidPosition(testX, testY, dungeons)) { dungeon.x = testX; dungeon.y = testY; validPosition = true; } attempts++; } // If no valid position found after 100 attempts, place anyway if (!validPosition) { dungeon.x = 150 + Math.random() * (2048 - 300); dungeon.y = 400 + Math.random() * (2732 - 800); } dungeons.push(dungeon); game.addChild(dungeon); } // Add UI levelText.setText('Level: ' + playerCharacter.level); levelText.x = 50; levelText.y = 150; game.addChild(levelText); // Add map indicator var mapText = new Text2('Map: ' + currentMap + ' (' + getMapRarity(currentMap) + ')', { size: 40, fill: 0xFFFFFF }); mapText.x = 50; mapText.y = 100; game.addChild(mapText); healthText.setText('Health: ' + playerCharacter.health + '/' + playerCharacter.maxHealth); healthText.x = 50; healthText.y = 200; game.addChild(healthText); // Add restart admin button var restartButton = game.attachAsset('backButton', { anchorX: 0.5, anchorY: 0.5, x: 2048 - 100, y: 100 }); } // Setup combat function setupCombat() { game.removeChildren(); // Add combat background var combatBg = game.attachAsset('combatBackground', { anchorX: 0, anchorY: 0, x: 0, y: 0 }); // Position character fixed on left side for side-scrolling playerCharacter.x = 200; playerCharacter.y = 1866; game.addChild(playerCharacter); // Add back button backButton = game.attachAsset('backButton', { anchorX: 0.5, anchorY: 0.5, x: 100, y: 50 }); // Reset combat variables arrows = []; enemies = []; lootItems = []; overworldMonsters = []; lastEnemySpawn = 0; lastArrowShot = 0; lastOverworldMonsterSpawn = 0; lastOverworldArrowShot = 0; combatTimer = 0; enemiesKilled = 0; targetKills = 15; totalEnemiesSpawned = 0; // Add energy bar UI energyBarBg = game.attachAsset('energyBarBg', { anchorX: 0, anchorY: 0, x: 50, y: 2000 }); energyBar = game.attachAsset('energyBar', { anchorX: 0, anchorY: 0, x: 50, y: 2000 }); // Reset energy system currentEnergy = maxEnergy; energyRegenTimer = 1; isRegeneratingEnergy = false; wasEnergyDepleted = false; updateEnergyBar(); // Add level bar UI levelBarBg = game.attachAsset('levelBarBg', { anchorX: 0, anchorY: 0, x: 50, y: 2050 }); levelBarFill = game.attachAsset('levelBarFill', { anchorX: 0, anchorY: 0, x: 50, y: 2050 }); experienceText = new Text2('XP: 0/100', { size: 30, fill: 0xFFFFFF }); experienceText.x = 50; experienceText.y = 2080; game.addChild(experienceText); // Add level text below the level bar levelBarText = new Text2('Level: ' + playerCharacter.level, { size: 30, fill: 0xFFFFFF }); levelBarText.x = 50; levelBarText.y = 2110; game.addChild(levelBarText); updateLevelBar(); // Add UI updateCombatUI(); } function updateEnergyBar() { if (energyBar) { var energyPercentage = currentEnergy / maxEnergy; energyBar.width = 300 * energyPercentage; // Change color based on energy level if (energyPercentage > 0.6) { energyBar.tint = 0xFFD700; // Green } else if (energyPercentage > 0.3) { energyBar.tint = 0xffff00; // Yellow } else { energyBar.tint = 0xff0000; // Red } } } function updateLevelBar() { if (levelBarFill && experienceText) { var levelUpThreshold = playerCharacter.level * 100; var experiencePercentage = playerCharacter.experience / levelUpThreshold; levelBarFill.width = 400 * experiencePercentage; // Update experience text experienceText.setText('XP: ' + playerCharacter.experience + '/' + levelUpThreshold); // Update level text if (levelBarText) { levelBarText.setText('Level: ' + playerCharacter.level); } } } function updateCombatUI() { if (levelText.parent) { levelText.parent.removeChild(levelText); } if (healthText.parent) { healthText.parent.removeChild(healthText); } levelText.setText('Level: ' + playerCharacter.level); levelText.x = 50; levelText.y = 150; game.addChild(levelText); healthText.setText('Health: ' + playerCharacter.health + '/' + playerCharacter.maxHealth); healthText.x = 50; healthText.y = 200; game.addChild(healthText); // Update level bar updateLevelBar(); } function collectLoot(loot) { // Equip the item playerCharacter.equipment[loot.type] = loot; playerCharacter.calculateStats(); // Update character appearance updateCharacterAppearance(); // Remove from game loot.destroy(); var index = lootItems.indexOf(loot); if (index > -1) { lootItems.splice(index, 1); } // Save game data saveGameData(); updateCombatUI(); } function getMapRarity(mapNumber) { var rarities = ['common', 'rare', 'epic', 'legendary']; return rarities[Math.min(mapNumber - 1, 3)]; } function getDungeonProgressionKey(mapNumber, difficulty) { return 'map' + mapNumber + '_' + difficulty; } function getCompletedDungeonsForDifficulty(mapNumber, difficulty) { var key = getDungeonProgressionKey(mapNumber, difficulty); return gameData.completedDungeons[key] || 0; } function isDifficultyUnlocked(mapNumber, difficulty) { if (difficulty === 'easy') { return true; } if (difficulty === 'normal') { return getCompletedDungeonsForDifficulty(mapNumber, 'easy') >= 4; } if (difficulty === 'hard') { return getCompletedDungeonsForDifficulty(mapNumber, 'normal') >= 3; } if (difficulty === 'veryHard') { return getCompletedDungeonsForDifficulty(mapNumber, 'hard') >= 2; } return false; } function completeDungeon(mapNumber, difficulty, index) { var key = getDungeonProgressionKey(mapNumber, difficulty); gameData.completedDungeons[key] = (gameData.completedDungeons[key] || 0) + 1; // Give fixed loot based on difficulty and completion order var lootKey = 'map' + mapNumber + '_' + difficulty + '_' + index; if (!gameData.givenLoot[lootKey]) { var loot = getFixedLoot(mapNumber, difficulty, index); if (loot) { giveLoot(loot.type, loot.rarity); gameData.givenLoot[lootKey] = true; } } // Check if we should advance to next map or win the game if (difficulty === 'veryHard' && getCompletedDungeonsForDifficulty(mapNumber, 'veryHard') >= 1) { // Map 4 Very Hard completion wins the game if (mapNumber === 4) { LK.showYouWin(); return; } gameData.unlockedMaps = Math.max(gameData.unlockedMaps, mapNumber + 1); currentMap = mapNumber + 1; // Reset dungeon completion and loot tracking for new map resetMapProgress(mapNumber + 1); } saveGameData(); } function getFixedLoot(mapNumber, difficulty, index) { var rarity = getMapRarity(mapNumber); if (difficulty === 'easy') { // Only 1 of the Easy dungeons drops helmet - use a fixed random selection per map var helmetKey = 'map' + mapNumber + '_helmet_dungeon'; var helmetDungeonIndex = gameData.givenLoot[helmetKey]; if (helmetDungeonIndex === undefined) { // First time determining which easy dungeon drops helmet helmetDungeonIndex = Math.floor(Math.random() * 4); gameData.givenLoot[helmetKey] = helmetDungeonIndex; } if (index === helmetDungeonIndex) { return { type: 'helmet', rarity: rarity }; } } else if (difficulty === 'normal') { // Loot based on entry order, not dungeon index var orderKey = 'map' + mapNumber + '_normal_order'; var entryOrder = gameData.dungeonEntryOrder[orderKey] || []; var entryPosition = entryOrder.indexOf(index); if (entryPosition === 0) { return { type: 'boots', rarity: rarity }; } if (entryPosition === 1) { return { type: 'gloves', rarity: rarity }; } // Third normal dungeon entered has no drop } else if (difficulty === 'hard') { // Loot based on entry order, not dungeon index var orderKey = 'map' + mapNumber + '_hard_order'; var entryOrder = gameData.dungeonEntryOrder[orderKey] || []; var entryPosition = entryOrder.indexOf(index); if (entryPosition === 0) { return { type: 'armor', rarity: rarity }; } if (entryPosition === 1) { return { type: 'ring', rarity: rarity }; } } else if (difficulty === 'veryHard') { // VeryHard bow gets higher rarity than map base rarity var rarities = ['common', 'rare', 'epic', 'legendary']; var currentIndex = rarities.indexOf(rarity); var bowRarity = rarities[Math.min(currentIndex + 1, 3)]; return { type: 'bow', rarity: bowRarity }; } return null; } function createRingDrop(rarity, x, y) { // Create a proper loot item with stats var multiplier = { common: 1, rare: 2, epic: 3, legendary: 5 }; var loot = { type: 'ring', rarity: rarity, healthBonus: Math.floor(Math.random() * 20 * multiplier[rarity]), damageBonus: Math.floor(Math.random() * 10 * multiplier[rarity]), defenseBonus: Math.floor(Math.random() * 5 * multiplier[rarity]) }; // Create visual loot item at monster death position var visualLoot = new LootItem('ring', rarity, x, y); lootItems.push(visualLoot); game.addChild(visualLoot); LK.getSound('lootDrop').play(); } function giveLoot(type, rarity) { // Create a proper loot item with stats var multiplier = { common: 1, rare: 2, epic: 3, legendary: 5 }; var loot = { type: type, rarity: rarity, healthBonus: Math.floor(Math.random() * 20 * multiplier[rarity]), damageBonus: Math.floor(Math.random() * 10 * multiplier[rarity]), defenseBonus: Math.floor(Math.random() * 5 * multiplier[rarity]) }; // If we're in overworld and it's a ring, create a visual loot item if (currentState === 'overworld' && type === 'ring') { // Find the last killed monster position or use a default position var dropX = playerCharacter.x + (Math.random() - 0.5) * 200; var dropY = playerCharacter.y + (Math.random() - 0.5) * 200; // Create visual loot item var visualLoot = new LootItem(type, rarity, dropX, dropY); lootItems.push(visualLoot); game.addChild(visualLoot); } else { // For other cases or when in combat, equip directly playerCharacter.equipment[type] = loot; playerCharacter.calculateStats(); // Update character appearance updateCharacterAppearance(); } LK.getSound('lootDrop').play(); } function resetMapProgress(mapNumber) { // Don't reset progress, just ensure we're tracking the new map } function getCharacterAsset() { // Count equipped gear pieces (excluding necklace and ring) var hasHelmet = playerCharacter.equipment.helmet !== null; var hasBoots = playerCharacter.equipment.boots !== null; var hasGloves = playerCharacter.equipment.gloves !== null; var hasArmor = playerCharacter.equipment.armor !== null; var hasBow = playerCharacter.equipment.bow !== null; // Get helmet rarity (determines the set's base tier) var helmetRarity = hasHelmet ? playerCharacter.equipment.helmet.rarity : null; var bowRarity = hasBow ? playerCharacter.equipment.bow.rarity : null; // If no helmet, use default character if (!hasHelmet) { return 'character'; } // Define rarity levels var rarityLevels = { 'common': 0, 'rare': 1, 'epic': 2, 'legendary': 3 }; var helmetLevel = rarityLevels[helmetRarity]; var bowLevel = bowRarity ? rarityLevels[bowRarity] : -1; // Map 1: Common set (helmet=common, bow=rare) if (helmetLevel === 0) { if (hasHelmet && !hasBoots && !hasGloves && !hasArmor && !hasBow) { return 'ch1'; } if (hasHelmet && hasBoots && !hasGloves && !hasArmor && !hasBow) { return 'ch2'; } if (hasHelmet && hasBoots && hasGloves && !hasArmor && !hasBow) { return 'ch3'; } if (hasHelmet && hasBoots && hasGloves && hasArmor && !hasBow) { return 'ch4'; } if (hasHelmet && hasBoots && hasGloves && hasArmor && hasBow && bowLevel === 1) { return 'ch5'; } } // Map 2: Rare set (helmet=rare, bow=epic) if (helmetLevel === 1) { if (hasHelmet && !hasBoots && !hasGloves && !hasArmor && hasBow && bowLevel === 2) { return 'ch6'; } if (hasHelmet && hasBoots && !hasGloves && !hasArmor && hasBow && bowLevel === 2) { return 'ch7'; } if (hasHelmet && hasBoots && hasGloves && !hasArmor && hasBow && bowLevel === 2) { return 'ch8'; } if (hasHelmet && hasBoots && hasGloves && hasArmor && hasBow && bowLevel === 2) { return 'ch9'; } if (hasHelmet && hasBoots && hasGloves && hasArmor && hasBow && bowLevel === 3) { return 'ch10'; } } // Map 3: Epic set (helmet=epic, bow=legendary) if (helmetLevel === 2) { if (hasHelmet && !hasBoots && !hasGloves && !hasArmor && hasBow && bowLevel === 3) { return 'ch11'; } if (hasHelmet && hasBoots && !hasGloves && !hasArmor && hasBow && bowLevel === 3) { return 'ch12'; } if (hasHelmet && hasBoots && hasGloves && !hasArmor && hasBow && bowLevel === 3) { return 'ch13'; } if (hasHelmet && hasBoots && hasGloves && hasArmor && hasBow && bowLevel === 3) { return 'ch14'; } if (hasHelmet && hasBoots && hasGloves && hasArmor && hasBow && bowLevel === 3) { return 'ch15'; } } // Map 4: Legendary set (helmet=legendary, bow=legendary) if (helmetLevel === 3) { if (hasHelmet && !hasBoots && !hasGloves && !hasArmor && hasBow && bowLevel === 3) { return 'ch16'; } if (hasHelmet && hasBoots && !hasGloves && !hasArmor && hasBow && bowLevel === 3) { return 'ch17'; } if (hasHelmet && hasBoots && hasGloves && !hasArmor && hasBow && bowLevel === 3) { return 'ch18'; } if (hasHelmet && hasBoots && hasGloves && hasArmor && hasBow && bowLevel === 3) { return 'ch19'; } } // Fallback to default character return 'character'; } function updateCharacterAppearance() { // Get the appropriate asset based on equipment var assetName = getCharacterAsset(); // Remove current character graphics if (playerCharacter.children.length > 0) { playerCharacter.removeChildAt(0); } // Add new character graphics var characterGraphics = playerCharacter.attachAsset(assetName, { anchorX: 0.5, anchorY: 0.5 }); } function saveGameData() { storage.level = playerCharacter.level; storage.experience = playerCharacter.experience; storage.unlockedMaps = gameData.unlockedMaps; storage.completedDungeons = gameData.completedDungeons; storage.givenLoot = gameData.givenLoot; storage.dungeonEntryOrder = gameData.dungeonEntryOrder; // Save equipment properties individually - only save if equipment exists if (playerCharacter.equipment.helmet) { storage.equipmentHelmetType = playerCharacter.equipment.helmet.type; storage.equipmentHelmetRarity = playerCharacter.equipment.helmet.rarity; storage.equipmentHelmetHealthBonus = playerCharacter.equipment.helmet.healthBonus; storage.equipmentHelmetDamageBonus = playerCharacter.equipment.helmet.damageBonus; storage.equipmentHelmetDefenseBonus = playerCharacter.equipment.helmet.defenseBonus; } else { storage.equipmentHelmetType = null; } if (playerCharacter.equipment.boots) { storage.equipmentBootsType = playerCharacter.equipment.boots.type; storage.equipmentBootsRarity = playerCharacter.equipment.boots.rarity; storage.equipmentBootsHealthBonus = playerCharacter.equipment.boots.healthBonus; storage.equipmentBootsDamageBonus = playerCharacter.equipment.boots.damageBonus; storage.equipmentBootsDefenseBonus = playerCharacter.equipment.boots.defenseBonus; } else { storage.equipmentBootsType = null; } if (playerCharacter.equipment.armor) { storage.equipmentArmorType = playerCharacter.equipment.armor.type; storage.equipmentArmorRarity = playerCharacter.equipment.armor.rarity; storage.equipmentArmorHealthBonus = playerCharacter.equipment.armor.healthBonus; storage.equipmentArmorDamageBonus = playerCharacter.equipment.armor.damageBonus; storage.equipmentArmorDefenseBonus = playerCharacter.equipment.armor.defenseBonus; } else { storage.equipmentArmorType = null; } if (playerCharacter.equipment.bow) { storage.equipmentBowType = playerCharacter.equipment.bow.type; storage.equipmentBowRarity = playerCharacter.equipment.bow.rarity; storage.equipmentBowHealthBonus = playerCharacter.equipment.bow.healthBonus; storage.equipmentBowDamageBonus = playerCharacter.equipment.bow.damageBonus; storage.equipmentBowDefenseBonus = playerCharacter.equipment.bow.defenseBonus; } else { storage.equipmentBowType = null; } if (playerCharacter.equipment.necklace) { storage.equipmentNecklaceType = playerCharacter.equipment.necklace.type; storage.equipmentNecklaceRarity = playerCharacter.equipment.necklace.rarity; storage.equipmentNecklaceHealthBonus = playerCharacter.equipment.necklace.healthBonus; storage.equipmentNecklaceDamageBonus = playerCharacter.equipment.necklace.damageBonus; storage.equipmentNecklaceDefenseBonus = playerCharacter.equipment.necklace.defenseBonus; } else { storage.equipmentNecklaceType = null; } if (playerCharacter.equipment.ring) { storage.equipmentRingType = playerCharacter.equipment.ring.type; storage.equipmentRingRarity = playerCharacter.equipment.ring.rarity; storage.equipmentRingHealthBonus = playerCharacter.equipment.ring.healthBonus; storage.equipmentRingDamageBonus = playerCharacter.equipment.ring.damageBonus; storage.equipmentRingDefenseBonus = playerCharacter.equipment.ring.defenseBonus; } else { storage.equipmentRingType = null; } if (playerCharacter.equipment.gloves) { storage.equipmentGlovesType = playerCharacter.equipment.gloves.type; storage.equipmentGlovesRarity = playerCharacter.equipment.gloves.rarity; storage.equipmentGlovesHealthBonus = playerCharacter.equipment.gloves.healthBonus; storage.equipmentGlovesDamageBonus = playerCharacter.equipment.gloves.damageBonus; storage.equipmentGlovesDefenseBonus = playerCharacter.equipment.gloves.defenseBonus; } else { storage.equipmentGlovesType = null; } } // Game input handlers var draggedCharacter = null; var dragOffset = { x: 0, y: 0 }; game.down = function (x, y, obj) { if (currentState === 'overworld') { // Check if clicking on restart button (positioned at top right) if (x >= 2048 - 160 && x <= 2048 - 40 && y >= 70 && y <= 130) { // Reset all game data storage.level = 1; storage.experience = 0; storage.unlockedMaps = 1; storage.completedDungeons = {}; storage.givenLoot = {}; storage.dungeonEntryOrder = {}; storage.equipmentHelmetType = null; storage.equipmentBootsType = null; storage.equipmentArmorType = null; storage.equipmentBowType = null; storage.equipmentNecklaceType = null; storage.equipmentRingType = null; storage.equipmentGlovesType = null; // Reset game state currentMap = 1; playerCharacter.level = 1; playerCharacter.experience = 0; playerCharacter.health = 100; playerCharacter.maxHealth = 100; playerCharacter.equipment = { helmet: null, boots: null, armor: null, bow: null, necklace: null, ring: null, gloves: null }; playerCharacter.calculateStats(); gameData.level = 1; gameData.experience = 0; gameData.unlockedMaps = 1; gameData.completedDungeons = {}; gameData.givenLoot = {}; gameData.dungeonEntryOrder = {}; gameData.equipment = playerCharacter.equipment; setupOverworld(); return; } // Check if clicking on character var localPos = playerCharacter.toLocal({ x: x, y: y }); if (localPos.x >= -40 && localPos.x <= 40 && localPos.y >= -40 && localPos.y <= 40) { draggedCharacter = playerCharacter; dragOffset.x = x - playerCharacter.x; dragOffset.y = y - playerCharacter.y; } } else if (currentState === 'combat' && backButton) { // Check if obj and obj.position exist, otherwise use x,y coordinates var localPos; if (obj && obj.position) { localPos = backButton.toLocal(obj.position); } else { // Convert game coordinates to local coordinates localPos = backButton.toLocal({ x: x, y: y }); } if (localPos.x >= -60 && localPos.x <= 60 && localPos.y >= -30 && localPos.y <= 30) { currentState = 'overworld'; setupOverworld(); } else { // Click to shoot - create homing arrow only if enemies are present and energy available // If energy was depleted (0), only allow shooting when fully regenerated var canShoot = enemies.length > 0 && currentEnergy > 0 && (!wasEnergyDepleted || currentEnergy === maxEnergy); if (canShoot) { var arrow = new Arrow(); arrow.x = playerCharacter.x + 50; arrow.y = playerCharacter.y; arrows.push(arrow); game.addChild(arrow); LK.getSound('shoot').play(); // Consume energy currentEnergy--; // Check if energy is now depleted if (currentEnergy === 0) { wasEnergyDepleted = true; } // Reset regeneration timer energyRegenTimer = 0; isRegeneratingEnergy = false; updateEnergyBar(); } } } }; game.move = function (x, y, obj) { if (currentState === 'overworld' && draggedCharacter) { draggedCharacter.x = x - dragOffset.x; draggedCharacter.y = y - dragOffset.y; } // Check for loot hover collection in overworld if (currentState === 'overworld') { for (var i = lootItems.length - 1; i >= 0; i--) { var loot = lootItems[i]; var dx = x - loot.x; var dy = y - loot.y; var distance = Math.sqrt(dx * dx + dy * dy); // If mouse is hovering over loot item (within 40 pixels) if (distance <= 40) { // Collect the loot playerCharacter.equipment[loot.type] = loot; playerCharacter.calculateStats(); updateCharacterAppearance(); // Remove from game loot.destroy(); lootItems.splice(i, 1); saveGameData(); break; } } } }; game.up = function (x, y, obj) { if (currentState === 'overworld' && draggedCharacter) { // Check if character is dropped on any dungeon for (var i = 0; i < dungeons.length; i++) { var dungeon = dungeons[i]; if (draggedCharacter.intersects(dungeon)) { currentState = 'combat'; currentDungeon = dungeon; setupCombat(); break; } } draggedCharacter = null; } }; // Main game update loop game.update = function () { if (currentState === 'overworld') { // Spawn overworld monsters slowly (every 5 seconds) if (LK.ticks - lastOverworldMonsterSpawn > 300) { var monster = new OverworldMonster(); // Initialize targeting flag monster.hasBeenTargeted = false; // Spawn at random position around the edges var spawnSide = Math.floor(Math.random() * 4); if (spawnSide === 0) { // Top monster.x = Math.random() * 2048; monster.y = 200; } else if (spawnSide === 1) { // Right monster.x = 1900; monster.y = 200 + Math.random() * 2332; } else if (spawnSide === 2) { // Bottom monster.x = Math.random() * 2048; monster.y = 2532; } else { // Left monster.x = 100; monster.y = 200 + Math.random() * 2332; } overworldMonsters.push(monster); game.addChild(monster); lastOverworldMonsterSpawn = LK.ticks; } // Auto-shoot arrows at overworld monsters - one arrow per monster within range (only if not already targeted) if (overworldMonsters.length > 0 && LK.ticks - lastOverworldArrowShot > 60) { var shootingRange = 1000; // Define shooting range var untargetedMonstersInRange = []; // Find monsters within range that haven't been targeted yet for (var m = 0; m < overworldMonsters.length; m++) { var monster = overworldMonsters[m]; var dx = monster.x - playerCharacter.x; var dy = monster.y - playerCharacter.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= shootingRange && !monster.hasBeenTargeted) { untargetedMonstersInRange.push(monster); } } // Shoot one arrow per untargeted monster in range for (var i = 0; i < untargetedMonstersInRange.length; i++) { var targetMonster = untargetedMonstersInRange[i]; var arrow = new Arrow(); arrow.x = playerCharacter.x; arrow.y = playerCharacter.y; arrows.push(arrow); game.addChild(arrow); // Mark this monster as targeted targetMonster.hasBeenTargeted = true; } // Play sound only if we shot any arrows if (untargetedMonstersInRange.length > 0) { LK.getSound('shoot').play(); } lastOverworldArrowShot = LK.ticks; } // Update overworld monsters for (var i = overworldMonsters.length - 1; i >= 0; i--) { var monster = overworldMonsters[i]; // Check collision with player if (monster.intersects(playerCharacter)) { playerCharacter.health -= 10; monster.destroy(); overworldMonsters.splice(i, 1); if (playerCharacter.health <= 0) { LK.showGameOver(); } // Update health display healthText.setText('Health: ' + playerCharacter.health + '/' + playerCharacter.maxHealth); continue; } } // Update arrows in overworld for (var i = arrows.length - 1; i >= 0; i--) { var arrow = arrows[i]; // Remove arrows that go off screen if (arrow.x > 2100 || arrow.x < -100 || arrow.y > 2800 || arrow.y < -100) { arrow.destroy(); arrows.splice(i, 1); continue; } // Check collision with overworld monsters for (var j = overworldMonsters.length - 1; j >= 0; j--) { var monster = overworldMonsters[j]; if (arrow.intersects(monster)) { monster.takeDamage(playerCharacter.damage); arrow.destroy(); arrows.splice(i, 1); if (monster.health <= 0) { monster.destroy(); overworldMonsters.splice(j, 1); } break; } } } } else if (currentState === 'combat') { combatTimer++; // Energy regeneration system if (currentEnergy < maxEnergy) { energyRegenTimer++; if (energyRegenTimer >= energyRegenDelay && !isRegeneratingEnergy) { isRegeneratingEnergy = true; } if (isRegeneratingEnergy) { // Regenerate energy over time using tween tween(this, {}, { duration: 200, onFinish: function onFinish() { if (currentEnergy < maxEnergy) { currentEnergy++; updateEnergyBar(); // Continue regenerating if not at max if (currentEnergy < maxEnergy) { energyRegenTimer = energyRegenDelay; } else { isRegeneratingEnergy = false; wasEnergyDepleted = false; // Reset depletion flag when fully regenerated } } } }); isRegeneratingEnergy = false; } } // Arrows are now fired on click instead of automatically // Spawn enemies from right side if (combatTimer - lastEnemySpawn > 120 && totalEnemiesSpawned < 15) { // Define enemy types available for each difficulty var enemyTypesByDifficulty = { easy: ['basic', 'fast'], normal: ['basic', 'fast', 'tank'], hard: ['basic', 'fast', 'tank', 'archer'], veryHard: ['basic', 'fast', 'tank', 'archer', 'boss'] }; var availableTypes = enemyTypesByDifficulty[currentDungeon.difficulty]; var randomType = availableTypes[Math.floor(Math.random() * availableTypes.length)]; var enemy = new Enemy(currentDungeon.difficulty, randomType); enemy.x = 1900; enemy.y = 1800; enemies.push(enemy); game.addChild(enemy); totalEnemiesSpawned++; lastEnemySpawn = combatTimer; } // Update arrows for (var i = arrows.length - 1; i >= 0; i--) { var arrow = arrows[i]; // Remove arrows that go off screen in any direction if (arrow.x > 2100 || arrow.x < -100 || arrow.y > 2800 || arrow.y < -100) { arrow.destroy(); arrows.splice(i, 1); continue; } // Check collision with enemies for (var j = enemies.length - 1; j >= 0; j--) { var enemy = enemies[j]; if (arrow.intersects(enemy)) { enemy.takeDamage(playerCharacter.damage); // Add visual feedback with tween tween(enemy.children[0], { tint: 0xFF0000 }, { duration: 200, onFinish: function onFinish() { tween(enemy.children[0], { tint: 0xFFFFFF }, { duration: 200 }); } }); arrow.destroy(); arrows.splice(i, 1); if (enemy.health <= 0) { enemy.destroy(); enemies.splice(j, 1); enemiesKilled++; // Check win condition if (totalEnemiesSpawned >= 15 && enemies.length === 0) { completeDungeon(currentMap, currentDungeon.difficulty, currentDungeon.index); LK.setTimeout(function () { currentState = 'overworld'; setupOverworld(); }, 1000); } } break; } } } // Update enemies for (var i = enemies.length - 1; i >= 0; i--) { var enemy = enemies[i]; if (enemy.x < -100) { enemy.destroy(); enemies.splice(i, 1); continue; } // Check collision with player if (enemy.intersects(playerCharacter)) { playerCharacter.health -= Math.max(1, enemy.damage - playerCharacter.defense); enemy.destroy(); enemies.splice(i, 1); if (playerCharacter.health <= 0) { LK.showGameOver(); } updateCombatUI(); } } // Update loot items (simple gravity effect) for (var i = 0; i < lootItems.length; i++) { var loot = lootItems[i]; if (loot.y < 1366) { loot.y += 2; } } } }; // Initialize the game setupOverworld();
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Arrow = Container.expand(function () {
var self = Container.call(this);
var arrowGraphics = self.attachAsset('arrow', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 5;
self.velocityX = 1; // Default rightward direction
self.velocityY = 0;
self.update = function () {
// Find closest target (enemy or overworld monster) for homing behavior
var closestTarget = null;
var closestDistance = Infinity;
// Check enemies first
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
var dx = enemy.x - self.x;
var dy = enemy.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < closestDistance) {
closestDistance = distance;
closestTarget = enemy;
}
}
// Check overworld monsters
for (var i = 0; i < overworldMonsters.length; i++) {
var monster = overworldMonsters[i];
var dx = monster.x - self.x;
var dy = monster.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < closestDistance) {
closestDistance = distance;
closestTarget = monster;
}
}
// Update direction toward closest target, or continue rightward if no targets
if (closestTarget && closestDistance > 10) {
// Avoid jitter when very close
var dx = closestTarget.x - self.x;
var dy = closestTarget.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
self.velocityX = dx / distance * self.speed;
self.velocityY = dy / distance * self.speed;
// Rotate arrow to face direction
arrowGraphics.rotation = Math.atan2(dy, dx);
} else if (!closestTarget) {
// No targets, travel rightward
self.velocityX = self.speed;
self.velocityY = 0;
arrowGraphics.rotation = 0;
}
// Move arrow
self.x += self.velocityX;
self.y += self.velocityY;
};
return self;
});
var Character = Container.expand(function () {
var self = Container.call(this);
var characterGraphics = self.attachAsset('character', {
anchorX: 0.5,
anchorY: 0.5
});
// Character stats
self.level = 1;
self.experience = 0;
self.health = 100;
self.maxHealth = 100;
self.damage = 10;
self.defense = 0;
// Equipment slots
self.equipment = {
helmet: null,
boots: null,
armor: null,
bow: null,
necklace: null,
ring: null,
gloves: null
};
self.calculateStats = function () {
self.maxHealth = 100 + self.level * 10;
self.damage = 10 + self.level * 2;
self.defense = 0 + self.level * 1;
// Add equipment bonuses
for (var slot in self.equipment) {
if (self.equipment[slot]) {
var item = self.equipment[slot];
self.maxHealth += item.healthBonus || 0;
self.damage += item.damageBonus || 0;
self.defense += item.defenseBonus || 0;
}
}
if (self.health > self.maxHealth) {
self.health = self.maxHealth;
}
};
self.gainExperience = function (amount) {
self.experience += amount;
var levelUpThreshold = self.level * 100;
if (self.experience >= levelUpThreshold) {
self.level++;
self.experience -= levelUpThreshold;
self.calculateStats();
self.health = self.maxHealth;
LK.getSound('levelUp').play();
}
// Update level bar if in combat
if (currentState === 'combat') {
updateLevelBar();
}
};
return self;
});
var Dungeon = Container.expand(function (difficulty, index) {
var self = Container.call(this);
var dungeonGraphics = self.attachAsset('dungeon', {
anchorX: 0.5,
anchorY: 0.5
});
self.difficulty = difficulty;
self.index = index;
self.isHovered = false;
// Difficulty colors
var colors = {
easy: 0x90EE90,
normal: 0xFFD700,
hard: 0xFF8C00,
veryHard: 0xFF4500
};
dungeonGraphics.tint = colors[difficulty];
// Add difficulty text
var difficultyNames = {
easy: 'EASY',
normal: 'NORMAL',
hard: 'HARD',
veryHard: 'VERY HARD'
};
var difficultyText = new Text2(difficultyNames[difficulty], {
size: 50,
fill: 0xFFFFFF
});
difficultyText.anchor.set(0.5, 1);
difficultyText.x = 0;
difficultyText.y = -80;
self.addChild(difficultyText);
self.down = function (x, y, obj) {
// Track entry order for normal and hard dungeons
if (difficulty === 'normal' || difficulty === 'hard') {
var orderKey = 'map' + currentMap + '_' + difficulty + '_order';
// Ensure gameData exists and is an object
if (!gameData || _typeof(gameData) !== 'object') {
gameData = {};
}
// Ensure gameData.dungeonEntryOrder exists as an object
if (!gameData.dungeonEntryOrder || _typeof(gameData.dungeonEntryOrder) !== 'object') {
gameData.dungeonEntryOrder = {};
}
// Ensure the specific order key exists as an array - with additional safety checks
try {
if (!gameData.dungeonEntryOrder[orderKey] || !Array.isArray(gameData.dungeonEntryOrder[orderKey])) {
gameData.dungeonEntryOrder[orderKey] = [];
}
// Add this dungeon index to entry order if not already present
if (gameData.dungeonEntryOrder[orderKey].indexOf(index) === -1) {
gameData.dungeonEntryOrder[orderKey].push(index);
}
} catch (e) {
// Fallback: reinitialize dungeonEntryOrder if there's any error
gameData.dungeonEntryOrder = {};
gameData.dungeonEntryOrder[orderKey] = [index];
}
}
currentState = 'combat';
currentDungeon = self;
setupCombat();
};
return self;
});
var Enemy = Container.expand(function (difficulty, enemyType) {
var self = Container.call(this);
// Select appropriate asset based on enemy type
var assetName = 'enemyBasic'; // default
if (enemyType === 'basic') {
assetName = 'enemyBasic';
} else if (enemyType === 'fast') {
assetName = 'enemyFast';
} else if (enemyType === 'tank') {
assetName = 'enemyTank';
} else if (enemyType === 'archer') {
assetName = 'enemyArcher';
} else if (enemyType === 'boss') {
assetName = 'enemyBoss';
}
var enemyGraphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
self.enemyType = enemyType || 'basic';
self.difficulty = difficulty;
// Base stats for different enemy types
var enemyStats = {
basic: {
health: 50,
speed: 1.6,
tint: 0xFFFFFF,
experience: 10,
damage: 20
},
fast: {
health: 30,
speed: 2.4,
tint: 0x00FF00,
experience: 15,
damage: 20
},
tank: {
health: 120,
speed: 1,
tint: 0xFF0000,
experience: 25,
damage: 30
},
archer: {
health: 40,
speed: 3,
tint: 0x0000FF,
experience: 20,
damage: 50
},
boss: {
health: 400,
speed: 1,
tint: 0xFF00FF,
experience: 50,
damage: 100
}
};
var stats = enemyStats[self.enemyType];
var healthMultiplier = {
easy: 1,
normal: 2,
hard: 4,
veryHard: 8
};
self.maxHealth = stats.health * healthMultiplier[difficulty];
self.health = self.maxHealth;
self.speed = stats.speed;
self.experienceReward = stats.experience;
self.damage = stats.damage;
// Apply visual tint based on enemy type
enemyGraphics.tint = stats.tint;
self.update = function () {
self.x -= self.speed;
};
self.takeDamage = function (damage) {
self.health -= damage;
if (self.health <= 0) {
self.die();
}
};
self.die = function () {
LK.getSound('enemyDeath').play();
playerCharacter.gainExperience(self.experienceReward);
};
return self;
});
var LootItem = Container.expand(function (type, rarity, x, y) {
var self = Container.call(this);
var lootGraphics = self.attachAsset(type, {
anchorX: 0.5,
anchorY: 0.5
});
self.type = type;
self.rarity = rarity;
// Rarity colors
var rarityColors = {
common: 0x808080,
rare: 0x4169e1,
epic: 0x8a2be2,
legendary: 0xffd700
};
lootGraphics.tint = rarityColors[rarity];
// Generate random stats based on rarity
var multiplier = {
common: 1,
rare: 2,
epic: 3,
legendary: 5
};
self.healthBonus = Math.floor(Math.random() * 20 * multiplier[rarity]);
self.damageBonus = Math.floor(Math.random() * 10 * multiplier[rarity]);
self.defenseBonus = Math.floor(Math.random() * 5 * multiplier[rarity]);
self.x = x;
self.y = y;
self.down = function (x, y, obj) {
collectLoot(self);
};
return self;
});
var OverworldMonster = Container.expand(function () {
var self = Container.call(this);
var monsterGraphics = self.attachAsset('ch23', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 1;
self.maxHealth = 1;
self.speed = 4; // Slow movement
self.lastX = 0;
self.lastY = 0;
self.update = function () {
// Track last position for collision detection
self.lastX = self.x;
self.lastY = self.y;
// Move slowly towards player
var dx = playerCharacter.x - self.x;
var dy = playerCharacter.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 5) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
};
self.takeDamage = function (damage) {
self.health -= damage;
if (self.health <= 0) {
self.die();
}
};
self.die = function () {
LK.getSound('enemyDeath').play();
playerCharacter.gainExperience(20);
// Store monster position for ring drop
var monsterX = self.x;
var monsterY = self.y;
// Ring drop chances
var randomChance = Math.random();
if (randomChance < 0.0000001) {
// 0.00000001 chance for legendary ring
createRingDrop('legendary', monsterX, monsterY);
} else if (randomChance < 0.000001) {
// 0.0000001 chance for epic ring
createRingDrop('epic', monsterX, monsterY);
} else if (randomChance < 0.00001) {
// 0.000001 chance for rare ring
createRingDrop('rare', monsterX, monsterY);
} else if (randomChance < 100) {
// 0.00001 chance for common ring
createRingDrop('common', monsterX, monsterY);
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Sounds
// UI assets
// Loot assets
// Combat assets
// Character and world assets
// Game state
function _typeof(o) {
"@babel/helpers - typeof";
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
return typeof o;
} : function (o) {
return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
}, _typeof(o);
}
var currentState = 'overworld'; // 'overworld', 'combat', 'inventory'
var currentMap = 1;
var currentDungeon = null;
var playerCharacter = new Character();
var dungeons = [];
var arrows = [];
var enemies = [];
var lootItems = [];
var overworldMonsters = [];
var lastEnemySpawn = 0;
var lastArrowShot = 0;
var lastOverworldMonsterSpawn = 0;
var lastOverworldArrowShot = 0;
var combatTimer = 0;
var enemiesKilled = 0;
var targetKills = 15;
var totalEnemiesSpawned = 0;
var maxEnergy = 5;
var currentEnergy = 5;
var energyRegenTimer = 1;
var energyRegenDelay = 50; // 0.3 seconds at 60fps
var isRegeneratingEnergy = false;
var wasEnergyDepleted = false;
var energyBar = null;
var energyBarBg = null;
var levelBarBg = null;
var levelBarFill = null;
var experienceText = null;
var levelBarText = null;
// UI elements
var levelText = new Text2('Level: 1', {
size: 40,
fill: 0xFFFFFF
});
var healthText = new Text2('Health: 100/100', {
size: 40,
fill: 0xFFFFFF
});
var backButton = null;
// Initialize storage with defaults
var gameData = {
level: storage.level || 1,
experience: storage.experience || 0,
equipment: {
helmet: null,
boots: null,
armor: null,
bow: null,
necklace: null,
ring: null,
gloves: null
},
unlockedMaps: storage.unlockedMaps || 1,
completedDungeons: storage.completedDungeons || {},
givenLoot: storage.givenLoot || {},
dungeonEntryOrder: storage.dungeonEntryOrder || {}
};
// Load equipment from storage
if (storage.equipmentHelmetType) {
gameData.equipment.helmet = {
type: storage.equipmentHelmetType,
rarity: storage.equipmentHelmetRarity,
healthBonus: storage.equipmentHelmetHealthBonus,
damageBonus: storage.equipmentHelmetDamageBonus,
defenseBonus: storage.equipmentHelmetDefenseBonus
};
}
if (storage.equipmentBootsType) {
gameData.equipment.boots = {
type: storage.equipmentBootsType,
rarity: storage.equipmentBootsRarity,
healthBonus: storage.equipmentBootsHealthBonus,
damageBonus: storage.equipmentBootsDamageBonus,
defenseBonus: storage.equipmentBootsDefenseBonus
};
}
if (storage.equipmentArmorType) {
gameData.equipment.armor = {
type: storage.equipmentArmorType,
rarity: storage.equipmentArmorRarity,
healthBonus: storage.equipmentArmorHealthBonus,
damageBonus: storage.equipmentArmorDamageBonus,
defenseBonus: storage.equipmentArmorDefenseBonus
};
}
if (storage.equipmentBowType) {
gameData.equipment.bow = {
type: storage.equipmentBowType,
rarity: storage.equipmentBowRarity,
healthBonus: storage.equipmentBowHealthBonus,
damageBonus: storage.equipmentBowDamageBonus,
defenseBonus: storage.equipmentBowDefenseBonus
};
}
if (storage.equipmentNecklaceType) {
gameData.equipment.necklace = {
type: storage.equipmentNecklaceType,
rarity: storage.equipmentNecklaceRarity,
healthBonus: storage.equipmentNecklaceHealthBonus,
damageBonus: storage.equipmentNecklaceDamageBonus,
defenseBonus: storage.equipmentNecklaceDefenseBonus
};
}
if (storage.equipmentRingType) {
gameData.equipment.ring = {
type: storage.equipmentRingType,
rarity: storage.equipmentRingRarity,
healthBonus: storage.equipmentRingHealthBonus,
damageBonus: storage.equipmentRingDamageBonus,
defenseBonus: storage.equipmentRingDefenseBonus
};
}
if (storage.equipmentGlovesType) {
gameData.equipment.gloves = {
type: storage.equipmentGlovesType,
rarity: storage.equipmentGlovesRarity,
healthBonus: storage.equipmentGlovesHealthBonus,
damageBonus: storage.equipmentGlovesDamageBonus,
defenseBonus: storage.equipmentGlovesDefenseBonus
};
}
// Load saved data
playerCharacter.level = gameData.level;
playerCharacter.experience = gameData.experience;
playerCharacter.equipment = gameData.equipment;
playerCharacter.calculateStats();
// Update character appearance based on loaded equipment
updateCharacterAppearance();
// Load dungeon progression
gameData.completedDungeons = storage.completedDungeons || {};
gameData.givenLoot = storage.givenLoot || {};
currentMap = storage.unlockedMaps || 1;
// Setup overworld
function setupOverworld() {
game.removeChildren();
// Add background
var background = game.attachAsset('mapBackground', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
});
// Add character at center
playerCharacter.x = 1024;
playerCharacter.y = 1366;
game.addChild(playerCharacter);
// Create dungeons in isometric grid
dungeons = [];
var allDifficulties = ['easy', 'easy', 'easy', 'easy', 'normal', 'normal', 'normal', 'hard', 'hard', 'veryHard'];
// Function to check if position is valid (at least 300 units away from existing dungeons and 300 from player)
function isValidPosition(x, y, existingDungeons) {
// Check distance from player starting position (1024, 1366)
var playerStartX = 1024;
var playerStartY = 1366;
var distanceFromPlayer = Math.sqrt(Math.pow(x - playerStartX, 2) + Math.pow(y - playerStartY, 2));
if (distanceFromPlayer < 300) {
return false;
}
// Check distance from existing dungeons using Euclidean distance
for (var i = 0; i < existingDungeons.length; i++) {
var dx = x - existingDungeons[i].x;
var dy = y - existingDungeons[i].y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 300) {
return false;
}
}
return true;
}
// Create all 10 dungeons but control their interaction based on progression
var difficultyIndices = {
easy: 0,
normal: 0,
hard: 0,
veryHard: 0
};
for (var i = 0; i < allDifficulties.length; i++) {
var difficulty = allDifficulties[i];
var dungeonIndex = difficultyIndices[difficulty];
var completedCount = getCompletedDungeonsForDifficulty(currentMap, difficulty);
var isUnlocked = isDifficultyUnlocked(currentMap, difficulty);
var isCompleted = dungeonIndex < completedCount;
// Skip creating completed dungeons (they should disappear)
if (isCompleted) {
difficultyIndices[difficulty]++;
continue;
}
var dungeon = new Dungeon(difficulty, dungeonIndex);
difficultyIndices[difficulty]++;
// Apply visual effects based on lock status
if (!isUnlocked) {
// Dim locked dungeons
dungeon.children[0].tint = 0x666666;
dungeon.children[0].alpha = 0.5;
// Disable interaction for locked dungeons
dungeon.down = null;
}
// Find valid position with minimum distance requirement
var validPosition = false;
var attempts = 0;
while (!validPosition && attempts < 100) {
var testX = 150 + Math.random() * (2048 - 300); // 150 to 1898
var testY = 400 + Math.random() * (2732 - 800); // 400 to 2332
if (isValidPosition(testX, testY, dungeons)) {
dungeon.x = testX;
dungeon.y = testY;
validPosition = true;
}
attempts++;
}
// If no valid position found after 100 attempts, place anyway
if (!validPosition) {
dungeon.x = 150 + Math.random() * (2048 - 300);
dungeon.y = 400 + Math.random() * (2732 - 800);
}
dungeons.push(dungeon);
game.addChild(dungeon);
}
// Add UI
levelText.setText('Level: ' + playerCharacter.level);
levelText.x = 50;
levelText.y = 150;
game.addChild(levelText);
// Add map indicator
var mapText = new Text2('Map: ' + currentMap + ' (' + getMapRarity(currentMap) + ')', {
size: 40,
fill: 0xFFFFFF
});
mapText.x = 50;
mapText.y = 100;
game.addChild(mapText);
healthText.setText('Health: ' + playerCharacter.health + '/' + playerCharacter.maxHealth);
healthText.x = 50;
healthText.y = 200;
game.addChild(healthText);
// Add restart admin button
var restartButton = game.attachAsset('backButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 - 100,
y: 100
});
}
// Setup combat
function setupCombat() {
game.removeChildren();
// Add combat background
var combatBg = game.attachAsset('combatBackground', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
});
// Position character fixed on left side for side-scrolling
playerCharacter.x = 200;
playerCharacter.y = 1866;
game.addChild(playerCharacter);
// Add back button
backButton = game.attachAsset('backButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 100,
y: 50
});
// Reset combat variables
arrows = [];
enemies = [];
lootItems = [];
overworldMonsters = [];
lastEnemySpawn = 0;
lastArrowShot = 0;
lastOverworldMonsterSpawn = 0;
lastOverworldArrowShot = 0;
combatTimer = 0;
enemiesKilled = 0;
targetKills = 15;
totalEnemiesSpawned = 0;
// Add energy bar UI
energyBarBg = game.attachAsset('energyBarBg', {
anchorX: 0,
anchorY: 0,
x: 50,
y: 2000
});
energyBar = game.attachAsset('energyBar', {
anchorX: 0,
anchorY: 0,
x: 50,
y: 2000
});
// Reset energy system
currentEnergy = maxEnergy;
energyRegenTimer = 1;
isRegeneratingEnergy = false;
wasEnergyDepleted = false;
updateEnergyBar();
// Add level bar UI
levelBarBg = game.attachAsset('levelBarBg', {
anchorX: 0,
anchorY: 0,
x: 50,
y: 2050
});
levelBarFill = game.attachAsset('levelBarFill', {
anchorX: 0,
anchorY: 0,
x: 50,
y: 2050
});
experienceText = new Text2('XP: 0/100', {
size: 30,
fill: 0xFFFFFF
});
experienceText.x = 50;
experienceText.y = 2080;
game.addChild(experienceText);
// Add level text below the level bar
levelBarText = new Text2('Level: ' + playerCharacter.level, {
size: 30,
fill: 0xFFFFFF
});
levelBarText.x = 50;
levelBarText.y = 2110;
game.addChild(levelBarText);
updateLevelBar();
// Add UI
updateCombatUI();
}
function updateEnergyBar() {
if (energyBar) {
var energyPercentage = currentEnergy / maxEnergy;
energyBar.width = 300 * energyPercentage;
// Change color based on energy level
if (energyPercentage > 0.6) {
energyBar.tint = 0xFFD700; // Green
} else if (energyPercentage > 0.3) {
energyBar.tint = 0xffff00; // Yellow
} else {
energyBar.tint = 0xff0000; // Red
}
}
}
function updateLevelBar() {
if (levelBarFill && experienceText) {
var levelUpThreshold = playerCharacter.level * 100;
var experiencePercentage = playerCharacter.experience / levelUpThreshold;
levelBarFill.width = 400 * experiencePercentage;
// Update experience text
experienceText.setText('XP: ' + playerCharacter.experience + '/' + levelUpThreshold);
// Update level text
if (levelBarText) {
levelBarText.setText('Level: ' + playerCharacter.level);
}
}
}
function updateCombatUI() {
if (levelText.parent) {
levelText.parent.removeChild(levelText);
}
if (healthText.parent) {
healthText.parent.removeChild(healthText);
}
levelText.setText('Level: ' + playerCharacter.level);
levelText.x = 50;
levelText.y = 150;
game.addChild(levelText);
healthText.setText('Health: ' + playerCharacter.health + '/' + playerCharacter.maxHealth);
healthText.x = 50;
healthText.y = 200;
game.addChild(healthText);
// Update level bar
updateLevelBar();
}
function collectLoot(loot) {
// Equip the item
playerCharacter.equipment[loot.type] = loot;
playerCharacter.calculateStats();
// Update character appearance
updateCharacterAppearance();
// Remove from game
loot.destroy();
var index = lootItems.indexOf(loot);
if (index > -1) {
lootItems.splice(index, 1);
}
// Save game data
saveGameData();
updateCombatUI();
}
function getMapRarity(mapNumber) {
var rarities = ['common', 'rare', 'epic', 'legendary'];
return rarities[Math.min(mapNumber - 1, 3)];
}
function getDungeonProgressionKey(mapNumber, difficulty) {
return 'map' + mapNumber + '_' + difficulty;
}
function getCompletedDungeonsForDifficulty(mapNumber, difficulty) {
var key = getDungeonProgressionKey(mapNumber, difficulty);
return gameData.completedDungeons[key] || 0;
}
function isDifficultyUnlocked(mapNumber, difficulty) {
if (difficulty === 'easy') {
return true;
}
if (difficulty === 'normal') {
return getCompletedDungeonsForDifficulty(mapNumber, 'easy') >= 4;
}
if (difficulty === 'hard') {
return getCompletedDungeonsForDifficulty(mapNumber, 'normal') >= 3;
}
if (difficulty === 'veryHard') {
return getCompletedDungeonsForDifficulty(mapNumber, 'hard') >= 2;
}
return false;
}
function completeDungeon(mapNumber, difficulty, index) {
var key = getDungeonProgressionKey(mapNumber, difficulty);
gameData.completedDungeons[key] = (gameData.completedDungeons[key] || 0) + 1;
// Give fixed loot based on difficulty and completion order
var lootKey = 'map' + mapNumber + '_' + difficulty + '_' + index;
if (!gameData.givenLoot[lootKey]) {
var loot = getFixedLoot(mapNumber, difficulty, index);
if (loot) {
giveLoot(loot.type, loot.rarity);
gameData.givenLoot[lootKey] = true;
}
}
// Check if we should advance to next map or win the game
if (difficulty === 'veryHard' && getCompletedDungeonsForDifficulty(mapNumber, 'veryHard') >= 1) {
// Map 4 Very Hard completion wins the game
if (mapNumber === 4) {
LK.showYouWin();
return;
}
gameData.unlockedMaps = Math.max(gameData.unlockedMaps, mapNumber + 1);
currentMap = mapNumber + 1;
// Reset dungeon completion and loot tracking for new map
resetMapProgress(mapNumber + 1);
}
saveGameData();
}
function getFixedLoot(mapNumber, difficulty, index) {
var rarity = getMapRarity(mapNumber);
if (difficulty === 'easy') {
// Only 1 of the Easy dungeons drops helmet - use a fixed random selection per map
var helmetKey = 'map' + mapNumber + '_helmet_dungeon';
var helmetDungeonIndex = gameData.givenLoot[helmetKey];
if (helmetDungeonIndex === undefined) {
// First time determining which easy dungeon drops helmet
helmetDungeonIndex = Math.floor(Math.random() * 4);
gameData.givenLoot[helmetKey] = helmetDungeonIndex;
}
if (index === helmetDungeonIndex) {
return {
type: 'helmet',
rarity: rarity
};
}
} else if (difficulty === 'normal') {
// Loot based on entry order, not dungeon index
var orderKey = 'map' + mapNumber + '_normal_order';
var entryOrder = gameData.dungeonEntryOrder[orderKey] || [];
var entryPosition = entryOrder.indexOf(index);
if (entryPosition === 0) {
return {
type: 'boots',
rarity: rarity
};
}
if (entryPosition === 1) {
return {
type: 'gloves',
rarity: rarity
};
}
// Third normal dungeon entered has no drop
} else if (difficulty === 'hard') {
// Loot based on entry order, not dungeon index
var orderKey = 'map' + mapNumber + '_hard_order';
var entryOrder = gameData.dungeonEntryOrder[orderKey] || [];
var entryPosition = entryOrder.indexOf(index);
if (entryPosition === 0) {
return {
type: 'armor',
rarity: rarity
};
}
if (entryPosition === 1) {
return {
type: 'ring',
rarity: rarity
};
}
} else if (difficulty === 'veryHard') {
// VeryHard bow gets higher rarity than map base rarity
var rarities = ['common', 'rare', 'epic', 'legendary'];
var currentIndex = rarities.indexOf(rarity);
var bowRarity = rarities[Math.min(currentIndex + 1, 3)];
return {
type: 'bow',
rarity: bowRarity
};
}
return null;
}
function createRingDrop(rarity, x, y) {
// Create a proper loot item with stats
var multiplier = {
common: 1,
rare: 2,
epic: 3,
legendary: 5
};
var loot = {
type: 'ring',
rarity: rarity,
healthBonus: Math.floor(Math.random() * 20 * multiplier[rarity]),
damageBonus: Math.floor(Math.random() * 10 * multiplier[rarity]),
defenseBonus: Math.floor(Math.random() * 5 * multiplier[rarity])
};
// Create visual loot item at monster death position
var visualLoot = new LootItem('ring', rarity, x, y);
lootItems.push(visualLoot);
game.addChild(visualLoot);
LK.getSound('lootDrop').play();
}
function giveLoot(type, rarity) {
// Create a proper loot item with stats
var multiplier = {
common: 1,
rare: 2,
epic: 3,
legendary: 5
};
var loot = {
type: type,
rarity: rarity,
healthBonus: Math.floor(Math.random() * 20 * multiplier[rarity]),
damageBonus: Math.floor(Math.random() * 10 * multiplier[rarity]),
defenseBonus: Math.floor(Math.random() * 5 * multiplier[rarity])
};
// If we're in overworld and it's a ring, create a visual loot item
if (currentState === 'overworld' && type === 'ring') {
// Find the last killed monster position or use a default position
var dropX = playerCharacter.x + (Math.random() - 0.5) * 200;
var dropY = playerCharacter.y + (Math.random() - 0.5) * 200;
// Create visual loot item
var visualLoot = new LootItem(type, rarity, dropX, dropY);
lootItems.push(visualLoot);
game.addChild(visualLoot);
} else {
// For other cases or when in combat, equip directly
playerCharacter.equipment[type] = loot;
playerCharacter.calculateStats();
// Update character appearance
updateCharacterAppearance();
}
LK.getSound('lootDrop').play();
}
function resetMapProgress(mapNumber) {
// Don't reset progress, just ensure we're tracking the new map
}
function getCharacterAsset() {
// Count equipped gear pieces (excluding necklace and ring)
var hasHelmet = playerCharacter.equipment.helmet !== null;
var hasBoots = playerCharacter.equipment.boots !== null;
var hasGloves = playerCharacter.equipment.gloves !== null;
var hasArmor = playerCharacter.equipment.armor !== null;
var hasBow = playerCharacter.equipment.bow !== null;
// Get helmet rarity (determines the set's base tier)
var helmetRarity = hasHelmet ? playerCharacter.equipment.helmet.rarity : null;
var bowRarity = hasBow ? playerCharacter.equipment.bow.rarity : null;
// If no helmet, use default character
if (!hasHelmet) {
return 'character';
}
// Define rarity levels
var rarityLevels = {
'common': 0,
'rare': 1,
'epic': 2,
'legendary': 3
};
var helmetLevel = rarityLevels[helmetRarity];
var bowLevel = bowRarity ? rarityLevels[bowRarity] : -1;
// Map 1: Common set (helmet=common, bow=rare)
if (helmetLevel === 0) {
if (hasHelmet && !hasBoots && !hasGloves && !hasArmor && !hasBow) {
return 'ch1';
}
if (hasHelmet && hasBoots && !hasGloves && !hasArmor && !hasBow) {
return 'ch2';
}
if (hasHelmet && hasBoots && hasGloves && !hasArmor && !hasBow) {
return 'ch3';
}
if (hasHelmet && hasBoots && hasGloves && hasArmor && !hasBow) {
return 'ch4';
}
if (hasHelmet && hasBoots && hasGloves && hasArmor && hasBow && bowLevel === 1) {
return 'ch5';
}
}
// Map 2: Rare set (helmet=rare, bow=epic)
if (helmetLevel === 1) {
if (hasHelmet && !hasBoots && !hasGloves && !hasArmor && hasBow && bowLevel === 2) {
return 'ch6';
}
if (hasHelmet && hasBoots && !hasGloves && !hasArmor && hasBow && bowLevel === 2) {
return 'ch7';
}
if (hasHelmet && hasBoots && hasGloves && !hasArmor && hasBow && bowLevel === 2) {
return 'ch8';
}
if (hasHelmet && hasBoots && hasGloves && hasArmor && hasBow && bowLevel === 2) {
return 'ch9';
}
if (hasHelmet && hasBoots && hasGloves && hasArmor && hasBow && bowLevel === 3) {
return 'ch10';
}
}
// Map 3: Epic set (helmet=epic, bow=legendary)
if (helmetLevel === 2) {
if (hasHelmet && !hasBoots && !hasGloves && !hasArmor && hasBow && bowLevel === 3) {
return 'ch11';
}
if (hasHelmet && hasBoots && !hasGloves && !hasArmor && hasBow && bowLevel === 3) {
return 'ch12';
}
if (hasHelmet && hasBoots && hasGloves && !hasArmor && hasBow && bowLevel === 3) {
return 'ch13';
}
if (hasHelmet && hasBoots && hasGloves && hasArmor && hasBow && bowLevel === 3) {
return 'ch14';
}
if (hasHelmet && hasBoots && hasGloves && hasArmor && hasBow && bowLevel === 3) {
return 'ch15';
}
}
// Map 4: Legendary set (helmet=legendary, bow=legendary)
if (helmetLevel === 3) {
if (hasHelmet && !hasBoots && !hasGloves && !hasArmor && hasBow && bowLevel === 3) {
return 'ch16';
}
if (hasHelmet && hasBoots && !hasGloves && !hasArmor && hasBow && bowLevel === 3) {
return 'ch17';
}
if (hasHelmet && hasBoots && hasGloves && !hasArmor && hasBow && bowLevel === 3) {
return 'ch18';
}
if (hasHelmet && hasBoots && hasGloves && hasArmor && hasBow && bowLevel === 3) {
return 'ch19';
}
}
// Fallback to default character
return 'character';
}
function updateCharacterAppearance() {
// Get the appropriate asset based on equipment
var assetName = getCharacterAsset();
// Remove current character graphics
if (playerCharacter.children.length > 0) {
playerCharacter.removeChildAt(0);
}
// Add new character graphics
var characterGraphics = playerCharacter.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
}
function saveGameData() {
storage.level = playerCharacter.level;
storage.experience = playerCharacter.experience;
storage.unlockedMaps = gameData.unlockedMaps;
storage.completedDungeons = gameData.completedDungeons;
storage.givenLoot = gameData.givenLoot;
storage.dungeonEntryOrder = gameData.dungeonEntryOrder;
// Save equipment properties individually - only save if equipment exists
if (playerCharacter.equipment.helmet) {
storage.equipmentHelmetType = playerCharacter.equipment.helmet.type;
storage.equipmentHelmetRarity = playerCharacter.equipment.helmet.rarity;
storage.equipmentHelmetHealthBonus = playerCharacter.equipment.helmet.healthBonus;
storage.equipmentHelmetDamageBonus = playerCharacter.equipment.helmet.damageBonus;
storage.equipmentHelmetDefenseBonus = playerCharacter.equipment.helmet.defenseBonus;
} else {
storage.equipmentHelmetType = null;
}
if (playerCharacter.equipment.boots) {
storage.equipmentBootsType = playerCharacter.equipment.boots.type;
storage.equipmentBootsRarity = playerCharacter.equipment.boots.rarity;
storage.equipmentBootsHealthBonus = playerCharacter.equipment.boots.healthBonus;
storage.equipmentBootsDamageBonus = playerCharacter.equipment.boots.damageBonus;
storage.equipmentBootsDefenseBonus = playerCharacter.equipment.boots.defenseBonus;
} else {
storage.equipmentBootsType = null;
}
if (playerCharacter.equipment.armor) {
storage.equipmentArmorType = playerCharacter.equipment.armor.type;
storage.equipmentArmorRarity = playerCharacter.equipment.armor.rarity;
storage.equipmentArmorHealthBonus = playerCharacter.equipment.armor.healthBonus;
storage.equipmentArmorDamageBonus = playerCharacter.equipment.armor.damageBonus;
storage.equipmentArmorDefenseBonus = playerCharacter.equipment.armor.defenseBonus;
} else {
storage.equipmentArmorType = null;
}
if (playerCharacter.equipment.bow) {
storage.equipmentBowType = playerCharacter.equipment.bow.type;
storage.equipmentBowRarity = playerCharacter.equipment.bow.rarity;
storage.equipmentBowHealthBonus = playerCharacter.equipment.bow.healthBonus;
storage.equipmentBowDamageBonus = playerCharacter.equipment.bow.damageBonus;
storage.equipmentBowDefenseBonus = playerCharacter.equipment.bow.defenseBonus;
} else {
storage.equipmentBowType = null;
}
if (playerCharacter.equipment.necklace) {
storage.equipmentNecklaceType = playerCharacter.equipment.necklace.type;
storage.equipmentNecklaceRarity = playerCharacter.equipment.necklace.rarity;
storage.equipmentNecklaceHealthBonus = playerCharacter.equipment.necklace.healthBonus;
storage.equipmentNecklaceDamageBonus = playerCharacter.equipment.necklace.damageBonus;
storage.equipmentNecklaceDefenseBonus = playerCharacter.equipment.necklace.defenseBonus;
} else {
storage.equipmentNecklaceType = null;
}
if (playerCharacter.equipment.ring) {
storage.equipmentRingType = playerCharacter.equipment.ring.type;
storage.equipmentRingRarity = playerCharacter.equipment.ring.rarity;
storage.equipmentRingHealthBonus = playerCharacter.equipment.ring.healthBonus;
storage.equipmentRingDamageBonus = playerCharacter.equipment.ring.damageBonus;
storage.equipmentRingDefenseBonus = playerCharacter.equipment.ring.defenseBonus;
} else {
storage.equipmentRingType = null;
}
if (playerCharacter.equipment.gloves) {
storage.equipmentGlovesType = playerCharacter.equipment.gloves.type;
storage.equipmentGlovesRarity = playerCharacter.equipment.gloves.rarity;
storage.equipmentGlovesHealthBonus = playerCharacter.equipment.gloves.healthBonus;
storage.equipmentGlovesDamageBonus = playerCharacter.equipment.gloves.damageBonus;
storage.equipmentGlovesDefenseBonus = playerCharacter.equipment.gloves.defenseBonus;
} else {
storage.equipmentGlovesType = null;
}
}
// Game input handlers
var draggedCharacter = null;
var dragOffset = {
x: 0,
y: 0
};
game.down = function (x, y, obj) {
if (currentState === 'overworld') {
// Check if clicking on restart button (positioned at top right)
if (x >= 2048 - 160 && x <= 2048 - 40 && y >= 70 && y <= 130) {
// Reset all game data
storage.level = 1;
storage.experience = 0;
storage.unlockedMaps = 1;
storage.completedDungeons = {};
storage.givenLoot = {};
storage.dungeonEntryOrder = {};
storage.equipmentHelmetType = null;
storage.equipmentBootsType = null;
storage.equipmentArmorType = null;
storage.equipmentBowType = null;
storage.equipmentNecklaceType = null;
storage.equipmentRingType = null;
storage.equipmentGlovesType = null;
// Reset game state
currentMap = 1;
playerCharacter.level = 1;
playerCharacter.experience = 0;
playerCharacter.health = 100;
playerCharacter.maxHealth = 100;
playerCharacter.equipment = {
helmet: null,
boots: null,
armor: null,
bow: null,
necklace: null,
ring: null,
gloves: null
};
playerCharacter.calculateStats();
gameData.level = 1;
gameData.experience = 0;
gameData.unlockedMaps = 1;
gameData.completedDungeons = {};
gameData.givenLoot = {};
gameData.dungeonEntryOrder = {};
gameData.equipment = playerCharacter.equipment;
setupOverworld();
return;
}
// Check if clicking on character
var localPos = playerCharacter.toLocal({
x: x,
y: y
});
if (localPos.x >= -40 && localPos.x <= 40 && localPos.y >= -40 && localPos.y <= 40) {
draggedCharacter = playerCharacter;
dragOffset.x = x - playerCharacter.x;
dragOffset.y = y - playerCharacter.y;
}
} else if (currentState === 'combat' && backButton) {
// Check if obj and obj.position exist, otherwise use x,y coordinates
var localPos;
if (obj && obj.position) {
localPos = backButton.toLocal(obj.position);
} else {
// Convert game coordinates to local coordinates
localPos = backButton.toLocal({
x: x,
y: y
});
}
if (localPos.x >= -60 && localPos.x <= 60 && localPos.y >= -30 && localPos.y <= 30) {
currentState = 'overworld';
setupOverworld();
} else {
// Click to shoot - create homing arrow only if enemies are present and energy available
// If energy was depleted (0), only allow shooting when fully regenerated
var canShoot = enemies.length > 0 && currentEnergy > 0 && (!wasEnergyDepleted || currentEnergy === maxEnergy);
if (canShoot) {
var arrow = new Arrow();
arrow.x = playerCharacter.x + 50;
arrow.y = playerCharacter.y;
arrows.push(arrow);
game.addChild(arrow);
LK.getSound('shoot').play();
// Consume energy
currentEnergy--;
// Check if energy is now depleted
if (currentEnergy === 0) {
wasEnergyDepleted = true;
}
// Reset regeneration timer
energyRegenTimer = 0;
isRegeneratingEnergy = false;
updateEnergyBar();
}
}
}
};
game.move = function (x, y, obj) {
if (currentState === 'overworld' && draggedCharacter) {
draggedCharacter.x = x - dragOffset.x;
draggedCharacter.y = y - dragOffset.y;
}
// Check for loot hover collection in overworld
if (currentState === 'overworld') {
for (var i = lootItems.length - 1; i >= 0; i--) {
var loot = lootItems[i];
var dx = x - loot.x;
var dy = y - loot.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// If mouse is hovering over loot item (within 40 pixels)
if (distance <= 40) {
// Collect the loot
playerCharacter.equipment[loot.type] = loot;
playerCharacter.calculateStats();
updateCharacterAppearance();
// Remove from game
loot.destroy();
lootItems.splice(i, 1);
saveGameData();
break;
}
}
}
};
game.up = function (x, y, obj) {
if (currentState === 'overworld' && draggedCharacter) {
// Check if character is dropped on any dungeon
for (var i = 0; i < dungeons.length; i++) {
var dungeon = dungeons[i];
if (draggedCharacter.intersects(dungeon)) {
currentState = 'combat';
currentDungeon = dungeon;
setupCombat();
break;
}
}
draggedCharacter = null;
}
};
// Main game update loop
game.update = function () {
if (currentState === 'overworld') {
// Spawn overworld monsters slowly (every 5 seconds)
if (LK.ticks - lastOverworldMonsterSpawn > 300) {
var monster = new OverworldMonster();
// Initialize targeting flag
monster.hasBeenTargeted = false;
// Spawn at random position around the edges
var spawnSide = Math.floor(Math.random() * 4);
if (spawnSide === 0) {
// Top
monster.x = Math.random() * 2048;
monster.y = 200;
} else if (spawnSide === 1) {
// Right
monster.x = 1900;
monster.y = 200 + Math.random() * 2332;
} else if (spawnSide === 2) {
// Bottom
monster.x = Math.random() * 2048;
monster.y = 2532;
} else {
// Left
monster.x = 100;
monster.y = 200 + Math.random() * 2332;
}
overworldMonsters.push(monster);
game.addChild(monster);
lastOverworldMonsterSpawn = LK.ticks;
}
// Auto-shoot arrows at overworld monsters - one arrow per monster within range (only if not already targeted)
if (overworldMonsters.length > 0 && LK.ticks - lastOverworldArrowShot > 60) {
var shootingRange = 1000; // Define shooting range
var untargetedMonstersInRange = [];
// Find monsters within range that haven't been targeted yet
for (var m = 0; m < overworldMonsters.length; m++) {
var monster = overworldMonsters[m];
var dx = monster.x - playerCharacter.x;
var dy = monster.y - playerCharacter.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= shootingRange && !monster.hasBeenTargeted) {
untargetedMonstersInRange.push(monster);
}
}
// Shoot one arrow per untargeted monster in range
for (var i = 0; i < untargetedMonstersInRange.length; i++) {
var targetMonster = untargetedMonstersInRange[i];
var arrow = new Arrow();
arrow.x = playerCharacter.x;
arrow.y = playerCharacter.y;
arrows.push(arrow);
game.addChild(arrow);
// Mark this monster as targeted
targetMonster.hasBeenTargeted = true;
}
// Play sound only if we shot any arrows
if (untargetedMonstersInRange.length > 0) {
LK.getSound('shoot').play();
}
lastOverworldArrowShot = LK.ticks;
}
// Update overworld monsters
for (var i = overworldMonsters.length - 1; i >= 0; i--) {
var monster = overworldMonsters[i];
// Check collision with player
if (monster.intersects(playerCharacter)) {
playerCharacter.health -= 10;
monster.destroy();
overworldMonsters.splice(i, 1);
if (playerCharacter.health <= 0) {
LK.showGameOver();
}
// Update health display
healthText.setText('Health: ' + playerCharacter.health + '/' + playerCharacter.maxHealth);
continue;
}
}
// Update arrows in overworld
for (var i = arrows.length - 1; i >= 0; i--) {
var arrow = arrows[i];
// Remove arrows that go off screen
if (arrow.x > 2100 || arrow.x < -100 || arrow.y > 2800 || arrow.y < -100) {
arrow.destroy();
arrows.splice(i, 1);
continue;
}
// Check collision with overworld monsters
for (var j = overworldMonsters.length - 1; j >= 0; j--) {
var monster = overworldMonsters[j];
if (arrow.intersects(monster)) {
monster.takeDamage(playerCharacter.damage);
arrow.destroy();
arrows.splice(i, 1);
if (monster.health <= 0) {
monster.destroy();
overworldMonsters.splice(j, 1);
}
break;
}
}
}
} else if (currentState === 'combat') {
combatTimer++;
// Energy regeneration system
if (currentEnergy < maxEnergy) {
energyRegenTimer++;
if (energyRegenTimer >= energyRegenDelay && !isRegeneratingEnergy) {
isRegeneratingEnergy = true;
}
if (isRegeneratingEnergy) {
// Regenerate energy over time using tween
tween(this, {}, {
duration: 200,
onFinish: function onFinish() {
if (currentEnergy < maxEnergy) {
currentEnergy++;
updateEnergyBar();
// Continue regenerating if not at max
if (currentEnergy < maxEnergy) {
energyRegenTimer = energyRegenDelay;
} else {
isRegeneratingEnergy = false;
wasEnergyDepleted = false; // Reset depletion flag when fully regenerated
}
}
}
});
isRegeneratingEnergy = false;
}
}
// Arrows are now fired on click instead of automatically
// Spawn enemies from right side
if (combatTimer - lastEnemySpawn > 120 && totalEnemiesSpawned < 15) {
// Define enemy types available for each difficulty
var enemyTypesByDifficulty = {
easy: ['basic', 'fast'],
normal: ['basic', 'fast', 'tank'],
hard: ['basic', 'fast', 'tank', 'archer'],
veryHard: ['basic', 'fast', 'tank', 'archer', 'boss']
};
var availableTypes = enemyTypesByDifficulty[currentDungeon.difficulty];
var randomType = availableTypes[Math.floor(Math.random() * availableTypes.length)];
var enemy = new Enemy(currentDungeon.difficulty, randomType);
enemy.x = 1900;
enemy.y = 1800;
enemies.push(enemy);
game.addChild(enemy);
totalEnemiesSpawned++;
lastEnemySpawn = combatTimer;
}
// Update arrows
for (var i = arrows.length - 1; i >= 0; i--) {
var arrow = arrows[i];
// Remove arrows that go off screen in any direction
if (arrow.x > 2100 || arrow.x < -100 || arrow.y > 2800 || arrow.y < -100) {
arrow.destroy();
arrows.splice(i, 1);
continue;
}
// Check collision with enemies
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (arrow.intersects(enemy)) {
enemy.takeDamage(playerCharacter.damage);
// Add visual feedback with tween
tween(enemy.children[0], {
tint: 0xFF0000
}, {
duration: 200,
onFinish: function onFinish() {
tween(enemy.children[0], {
tint: 0xFFFFFF
}, {
duration: 200
});
}
});
arrow.destroy();
arrows.splice(i, 1);
if (enemy.health <= 0) {
enemy.destroy();
enemies.splice(j, 1);
enemiesKilled++;
// Check win condition
if (totalEnemiesSpawned >= 15 && enemies.length === 0) {
completeDungeon(currentMap, currentDungeon.difficulty, currentDungeon.index);
LK.setTimeout(function () {
currentState = 'overworld';
setupOverworld();
}, 1000);
}
}
break;
}
}
}
// Update enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
if (enemy.x < -100) {
enemy.destroy();
enemies.splice(i, 1);
continue;
}
// Check collision with player
if (enemy.intersects(playerCharacter)) {
playerCharacter.health -= Math.max(1, enemy.damage - playerCharacter.defense);
enemy.destroy();
enemies.splice(i, 1);
if (playerCharacter.health <= 0) {
LK.showGameOver();
}
updateCombatUI();
}
}
// Update loot items (simple gravity effect)
for (var i = 0; i < lootItems.length; i++) {
var loot = lootItems[i];
if (loot.y < 1366) {
loot.y += 2;
}
}
}
};
// Initialize the game
setupOverworld();
arrow. In-Game asset. 2d. High contrast. No shadows
pixel necklace. In-Game asset. 2d. High contrast. No shadows
mağaranın hafif üstünden görünüşü olsun
brown pixel 2dd game boots. In-Game asset. 2d. High contrast. No shadows
pixel brown game helmet. In-Game asset. 2d. High contrast. No shadows
pixel brown gloves. In-Game asset. 2d. High contrast. No shadows
pixel gold ring for 2d game. In-Game asset. 2d. High contrast. No shadows
blue pixel bow for 2d game archer. In-Game asset. 2d. High contrast. No shadows
brown pixel light armor for 2d games. In-Game asset. 2d. High contrast. No shadows
kahve rengi kask ekle karaktere
karaktere kahverengi bot giydir bileklerine kadar
kahverengi eldiven giydir karaktere
kahverengi hafif zırh giydir karaktere
karakter elinde tuttuğu yayı mavi yap
kaskı mavi yap
adamın sadece ayakakbılarını mavi renge çevirir misin
adamın eldivenlerini mavi renge çevirir misin
koyu kahverengi olan bütün zırhı kaskı yayı ayakkabıyı eldiveni mavi renk yapar mısın
yayı parlak mor renk yapar mısın
kaskıda parlak mor renk yapar mısın
ayakkabıları da parlak mor renk yapar mısın
koyu kahverengi olan bütün zırhı kaskı yayı ayakkabıyı eldiveni parlak mor renk yapar mısın
yayı parlak altın rengi yapar mısın
kaskını parlak altın rengine çevirir misin
ayakkabılarını parlak altın rengine çevirir misin
eldivenlerini parlak altın rengine çevirir misin
koyu kahverengi olan bütün zırhını kaskını ayakkabısını eldivenini parlak yayını altın rengine çevirir misin
eldivenlerini parlak mor renk yapar mısın
demon rabbit with red eyes. In-Game asset. 2d. High contrast. No shadows
sağ üst köşeye çevresinde eski tahta çitler olan çok küçük bir köy ekle
sağ üst köşeye bir kasaba ekle
sağ üst köşeye surla çevrili bir şehir ekle
sağ üstteki şehrin grafik açısından boyutunu çok değiştirmeden belki sadece biraz daha uzaktan bakar gibi ama çok daha gelişmiş bir şehre dönüştürür müsün
bu zindan girişini bir tık daha korkutucu göster mesela etrafındaki taşlarında üstünde kemikler en üst ortadaki taşında kemikten bir hayvvan başı gibi
mağaranın grafik ayarları ve boyutunu bozmadan taşların üzerinden lavlar akıyor gibi gözüksün zindan girişinin ortasındada kırmızı korkutucu bir sihirli geçit olsun
zindan girişi taşlarının üstüne mavi maden damarları gibi çizgiler ekle
kemik görünümünde bir kurt. In-Game asset. 2d. High contrast. No shadows
kemikten bir şovalye istiyorum biraz kambur dursun. In-Game asset. 2d. High contrast. No shadows
yıldırımlarla kaplı bir canavar istiyorum hafif kambur duruşlu biraz zombi gibi. In-Game asset. 2d. High contrast. No shadows
lavlarla kaplı bir canavar istiyorum kambur ve biraz iri yapılı. In-Game asset. 2d. High contrast. No shadows
kemikten oluşsun
yıldırımdan bir kartala dönüştür
sağdan sola doğru uçuyor gibi bir görüntü olsun
sağdan sola yürüyen bir cehennem şeytanı. In-Game asset. 2d. High contrast. No shadows
güçlü ve iri yapılı şeytan kral sağdan sola yürüyormuş gibi. In-Game asset. 2d. High contrast. No shadows
ölümsüz kemikler kralı sağdan sola yürüyor gibi. In-Game asset. 2d. High contrast. No shadows
aslan ve insan karışımı yıldırımla kaplı bir canavar kralı sağdan sola yürüyen. In-Game asset. 2d. High contrast. No shadows
Images Sounds Music Images › map1man map1man Size 200 × 200 Aspect Ratio Preserve Aspect Ratio Shape Box Color #365bb5 bastonlu yaşlı uzun sakallı kambur kel bir dede sağdan sola yürüyen üstünde ortaçağ fakir köylerinde köyün muhtarı kıyafeti olsun. In-Game asset. 2d. High contrast. No shadows. In-Game asset. 2d. High contrast. No shadows
şovalye kıyafetli orta yaşlı bir adam belinde kılıcıyla sağdan sola yürür gibi. In-Game asset. 2d. High contrast. No shadows
bir orta çağ şehrinin soylu dükü görünümünde yap orta yaşlarda sağdan solda yürür gibi. In-Game asset. 2d. High contrast. No shadows
bir imparatorluğun kralı , sağdan sola yürür gibi. In-Game asset. 2d. High contrast. No shadows