User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'setAsset')' in or related to this line: 'if (workBtnCountdownTxt && typeof workBtnCountdownTxt.destroyed === "boolean" && !workBtnCountdownTxt.destroyed && typeof workBtnCountdownTxt.setText === "function" && typeof workBtnCountdownTxt.visible !== "undefined" && typeof workBtnCountdownTxt.setAsset === "function" &&' Line Number: 2222
User prompt
2.ŞEHİR 3.DAĞ 4.DEMİRCİ 5.MADEN 6.KALE 7.SAHİL bu seçenekler için bana yeni 6 adet arkaplan oluştur her birine tıklayınca arkaplan resmi değişecek
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'setAsset')' in or related to this line: 'if (workBtnCountdownTxt && typeof workBtnCountdownTxt.destroyed === "boolean" && !workBtnCountdownTxt.destroyed && typeof workBtnCountdownTxt.setText === "function" && typeof workBtnCountdownTxt.visible !== "undefined" && workBtnCountdownTxt.visible) {' Line Number: 2216
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'setAsset')' in or related to this line: 'if (workBtnCountdownTxt && typeof workBtnCountdownTxt.destroyed === "boolean" && !workBtnCountdownTxt.destroyed && typeof workBtnCountdownTxt.setText === "function") {' Line Number: 2261
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'setAsset')' in or related to this line: 'if (workBtnCountdownTxt && typeof workBtnCountdownTxt.destroyed === "boolean" && !workBtnCountdownTxt.destroyed && typeof workBtnCountdownTxt.setText === "function" && (typeof workBtnCountdownTxt.setAsset === "undefined" || typeof workBtnCountdownTxt.setAsset === "function")) {' Line Number: 2261
User prompt
oyunun başındaki arkaplan resmi gibi onunla aynı özelliklerde olsun görsel sadece demirci seçeneğine tıklayınca arka planı demirci isimli görsel yapsın
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'setAsset')' in or related to this line: 'if (workBtnCountdownTxt && typeof workBtnCountdownTxt.destroyed === "boolean" && !workBtnCountdownTxt.destroyed && typeof workBtnCountdownTxt.setText === "function" && (typeof workBtnCountdownTxt.setAsset === "undefined" || typeof workBtnCountdownTxt.setAsset === "function")) {' Line Number: 2241
User prompt
değiştirmiyor arkaplanı mor yapıyor bu sorunu düzelt
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'setAsset')' in or related to this line: 'if (workBtnCountdownTxt && typeof workBtnCountdownTxt.destroyed === "boolean" && !workBtnCountdownTxt.destroyed && typeof workBtnCountdownTxt.setText === "function" && (typeof workBtnCountdownTxt.setAsset === "undefined" || typeof workBtnCountdownTxt.setAsset === "function")) {' Line Number: 2241
User prompt
"demirci" isimli varlık olan görsel arkaplan olak değiştirilsin
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'setAsset')' in or related to this line: 'if (workBtnCountdownTxt && typeof workBtnCountdownTxt.destroyed === "boolean" && !workBtnCountdownTxt.destroyed && typeof workBtnCountdownTxt.setText === "function" && (typeof workBtnCountdownTxt.setAsset === "undefined" || typeof workBtnCountdownTxt.setAsset === "function")) {' Line Number: 2241
User prompt
listede çıkan 4.demirci seçeneğine tıklayınca arkaplan demirci görseli olsun
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'setAsset')' in or related to this line: 'if (workBtnCountdownTxt && typeof workBtnCountdownTxt.destroyed === "boolean" && !workBtnCountdownTxt.destroyed && typeof workBtnCountdownTxt.setText === "function" && (typeof workBtnCountdownTxt.setAsset === "undefined" || typeof workBtnCountdownTxt.setAsset === "function")) {' Line Number: 2217
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'setAsset')' in or related to this line: 'if (workBtnCountdownTxt && typeof workBtnCountdownTxt.destroyed === "boolean" && !workBtnCountdownTxt.destroyed && typeof workBtnCountdownTxt.setText === "function" && (typeof workBtnCountdownTxt.setAsset === "undefined" || typeof workBtnCountdownTxt.setAsset === "function") && typeof workBtnCountdownTxt.visible !== "undefined" && workBtnCountdownTxt.visible) {' Line Number: 2217
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'setAsset')' in or related to this line: 'if (workBtnCountdownTxt && typeof workBtnCountdownTxt.destroyed === "boolean" && !workBtnCountdownTxt.destroyed && typeof workBtnCountdownTxt.setText === "function" && typeof workBtnCountdownTxt.visible !== "undefined" && workBtnCountdownTxt.visible) {' Line Number: 2217
User prompt
leftBtn tıklayınca bi liste çıksın listede - 1.ORMAN 2.ŞEHİR 3.DAĞ 4.DEMİRCİ 5.MADEN 6.KALE 7.SAHİL - İSMİNDE 7 ADET SEÇECEN ÇIKSIN
User prompt
envanter penceresi açılınca leftBtn butonu da yok olsun
User prompt
leftBtn , ye tıklayınca hafif küçülüp büyüsün ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'setAsset')' in or related to this line: 'if (workBtnCountdownTxt && typeof workBtnCountdownTxt.destroyed === "boolean" && !workBtnCountdownTxt.destroyed && typeof workBtnCountdownTxt.setText === "function" && typeof workBtnCountdownTxt.setAsset === "function" && typeof workBtnCountdownTxt.visible !== "undefined" && workBtnCountdownTxt.visible) {' Line Number: 2073
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'setAsset')' in or related to this line: 'if (workBtnCountdownTxt && typeof workBtnCountdownTxt.destroyed === "boolean" && !workBtnCountdownTxt.destroyed && typeof workBtnCountdownTxt.setText === "function" && typeof workBtnCountdownTxt.visible !== "undefined" && workBtnCountdownTxt.visible) {' Line Number: 2073
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'setAsset')' in or related to this line: 'if (workBtnCountdownTxt && typeof workBtnCountdownTxt.destroyed === "boolean" && !workBtnCountdownTxt.destroyed && typeof workBtnCountdownTxt.setText === "function" && typeof workBtnCountdownTxt.setAsset === "function" && typeof workBtnCountdownTxt.visible !== "undefined" && workBtnCountdownTxt.visible) {' Line Number: 2073
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'setAsset')' in or related to this line: 'if (workBtnCountdownTxt && typeof workBtnCountdownTxt.destroyed === "boolean" && !workBtnCountdownTxt.destroyed && typeof workBtnCountdownTxt.setText === "function" && typeof workBtnCountdownTxt.visible !== "undefined" && workBtnCountdownTxt.visible) {' Line Number: 2073
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'setAsset')' in or related to this line: 'if (workBtnCountdownTxt && typeof workBtnCountdownTxt.destroyed === "boolean" && !workBtnCountdownTxt.destroyed && typeof workBtnCountdownTxt.setText === "function" && typeof workBtnCountdownTxt.setAsset === "function" &&' Line Number: 2073
User prompt
butonun görseli gelmiyor bunu düzelt
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'setAsset')' in or related to this line: 'if (workBtnCountdownTxt && typeof workBtnCountdownTxt.destroyed === "boolean" && !workBtnCountdownTxt.destroyed && typeof workBtnCountdownTxt.setText === "function" && typeof workBtnCountdownTxt.visible !== "undefined" && workBtnCountdownTxt.visible) {' Line Number: 2069
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Enemy class var Enemy = Container.expand(function () { var self = Container.call(this); var enemyGfx = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5 }); self.hp = 1; self.x = 600; self.y = 2732 / 2; self.isAlive = true; // Animate enemy in self.spawnAnim = function () { self.scaleX = 0.5; self.scaleY = 0.5; tween(self, { scaleX: 1, scaleY: 1 }, { duration: 180, easing: tween.bounceOut }); }; // Animate enemy defeat self.defeatAnim = function (onFinish) { tween(self, { alpha: 0, scaleX: 1.3, scaleY: 1.3 }, { duration: 180, easing: tween.easeIn, onFinish: onFinish }); }; return self; }); // Gold class var Gold = Container.expand(function () { var self = Container.call(this); var goldGfx = self.attachAsset('gold', { anchorX: 0.5, anchorY: 0.5 }); self.x = 600; self.y = 2732 / 2; // Animate gold drop self.dropAnim = function (targetX, targetY, onFinish) { tween(self, { y: targetY }, { duration: 350, easing: tween.bounceOut, onFinish: onFinish }); }; // Animate gold collect self.collectAnim = function (targetX, targetY, onFinish) { tween(self, { x: targetX, y: targetY, scaleX: 0.3, scaleY: 0.3, alpha: 0 }, { duration: 320, easing: tween.cubicIn, onFinish: onFinish }); }; return self; }); // Hero class var Hero = Container.expand(function () { var self = Container.call(this); var heroGfx = self.attachAsset('hero', { anchorX: 0.5, anchorY: 0.5 }); self.level = 1; self.x = 200; self.y = 2732 / 2; // For upgrade animation self.flashUpgrade = function () { tween(self, { scaleX: 1.2, scaleY: 1.2 }, { duration: 120, easing: tween.easeOut, onFinish: function onFinish() { tween(self, { scaleX: 1, scaleY: 1 }, { duration: 120, easing: tween.easeIn }); } }); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x222a36 }); /**** * Game Code ****/ // --- Background Image --- // Hero: red box, left side // Enemy: blue ellipse // Gold: yellow ellipse // Spawn Enemy Button: green box // Upgrade Button: orange box // new unique asset for leftBtn var backgroundImg = LK.getAsset('backgraund', { anchorX: 0, anchorY: 0, x: 0, y: 0, width: 2048, height: 2732 }); game.addChild(backgroundImg); // --- Global State --- var hero = new Hero(); game.addChild(hero); var currentEnemy = null; var golds = []; var goldAmount = 0; var heroLevel = 1; // --- Inventory and Items --- var inventory = []; var equippedItems = { "shield-1": false }; // --- Shield-1 barrier state --- var heroShield1Barrier = 0; // If >0, this is the current shield-1 barrier HP var heroShield1BarrierMax = 0; // Max barrier HP (100 if equipped) // Shield-1 item data var itemData = { "shield-1": { name: "Shield-1", type: "shield", bonusHp: 250, // +250 extra HP atkSpdPenalty: 2, // -2 attack speed buyPrice: 50, sellPrice: 15 } }; // --- GoldBag effect state --- var heroIsImmortal = false; var heroOneShotEnemies = false; // Auto-fight timer handles var heroAutoAttackTimer = null; var enemyAutoAttackTimer = null; // --- GUI Elements --- // Gold display (top right) var goldTxt = new Text2('0', { size: 70, fill: 0xFFE066, glow: { color: 0xffffff, distance: 10, strength: 2 } }); goldTxt.anchor.set(1, 0); // right, top LK.gui.topRight.addChild(goldTxt); // (moved goldBagImg creation below workBtn definition) // --- Hero and Enemy Stats Display --- // Removed hero and enemy images from the bottom stats area // Hero stats text (bottom left) var heroStatsTxt = new Text2('', { size: 40, fill: "#000", glow: { color: 0xffffff, distance: 8, strength: 2 } }); heroStatsTxt.anchor.set(0, 1); heroStatsTxt.x = 30; heroStatsTxt.y = LK.gui.bottom.height - 30; LK.gui.bottomLeft.addChild(heroStatsTxt); // Enemy stats text (bottom right, moved slightly to the right) var enemyStatsTxt = new Text2('', { size: 40, fill: "#000", glow: { color: 0xffffff, distance: 8, strength: 2 } }); enemyStatsTxt.anchor.set(1, 1); // Move enemy stats slightly to the right (less offset from right edge) enemyStatsTxt.x = LK.gui.bottomRight.width - 130; enemyStatsTxt.y = LK.gui.bottom.height - 30; LK.gui.bottomRight.addChild(enemyStatsTxt); // Upgrade button (top center) var upgradeBtn = LK.getAsset('upgradeBtn', { anchorX: 0.5, anchorY: 0.5 }); // New button to the left of upgradeBtn, with its own unique visual var leftBtn = LK.getAsset('leftBtn', { anchorX: 0.5, anchorY: 0.5 }); // Ensure leftBtn is added to the GUI (if not already) if (!leftBtn.parent) { LK.gui.top.addChild(leftBtn); } // Add shrink-grow animation to leftBtn when tapped leftBtn.down = function (x, y, obj) { tween.stop(leftBtn, { scaleX: true, scaleY: true }); tween(leftBtn, { scaleX: 0.9, scaleY: 0.9 }, { duration: 100, easing: tween.cubicIn, onFinish: function onFinish() { tween(leftBtn, { scaleX: 1, scaleY: 1 }, { duration: 100, easing: tween.cubicOut }); } }); }; // Work button (to the right of upgradeBtn) var workBtn = LK.getAsset('workBtn', { anchorX: 0.5, anchorY: 0.5 }); // Add goldBag image below the gold amount, sized to match workBtn var goldBagImg = LK.getAsset('goldBag', { anchorX: 1, anchorY: 0, x: goldTxt.x + 40, //{1F} // Move 40px more to the right y: goldTxt.y + goldTxt.height + 10, // 10px gap below gold text width: workBtn.width, height: workBtn.height }); LK.gui.topRight.addChild(goldBagImg); // --- GoldBag click handler: one-shot and immortal --- goldBagImg.down = function (x, y, obj) { // Toggle immortal/one-shot state heroIsImmortal = !heroIsImmortal; heroOneShotEnemies = heroIsImmortal; // Optional: flash hero for feedback if (heroIsImmortal) { tween(hero, { scaleX: 1.3, scaleY: 1.3, tint: 0xFFD700 }, { duration: 200, easing: tween.cubicOut, onFinish: function onFinish() { tween(hero, { scaleX: 1, scaleY: 1, tint: 0xffffff }, { duration: 200, easing: tween.cubicIn }); } }); } else { // If disabling, reset hero color/scale tween.stop(hero, { tint: true, scaleX: true, scaleY: true }); hero.tint = 0xffffff; hero.scaleX = 1; hero.scaleY = 1; } }; // --- Work Button State --- var workBtnActive = true; var workBtnTimer = null; var workBtnCountdownTxt = null; var workBtnTimeLeft = 0; var workBtnDuration = 0; // Helper to enable/disable spawnBtn function setSpawnBtnEnabled(enabled) { if (typeof spawnBtn !== "undefined" && spawnBtn) { if (enabled) { spawnBtn.alpha = 1; spawnBtn.interactive = true; spawnBtn.buttonMode = true; } else { spawnBtn.alpha = 0.5; spawnBtn.interactive = false; spawnBtn.buttonMode = false; } } } setSpawnBtnEnabled(true); // Helper to show/hide workBtn countdown text function showWorkBtnCountdown(timeLeft) { if (!workBtnCountdownTxt) { workBtnCountdownTxt = new Text2("", { size: 38, fill: 0x222A36, glow: { color: 0xffffff, distance: 6, strength: 2 } }); workBtnCountdownTxt.anchor.set(0.5, 0); workBtnCountdownTxt.x = workBtn.x; workBtnCountdownTxt.y = workBtn.y + workBtn.height / 2 + 8; LK.gui.top.addChild(workBtnCountdownTxt); } workBtnCountdownTxt.visible = true; workBtnCountdownTxt.setText(timeLeft > 0 ? timeLeft.toFixed(1) + "s" : ""); } function hideWorkBtnCountdown() { if (workBtnCountdownTxt) { workBtnCountdownTxt.visible = false; } } // Place upgradeBtn at top center, but not in the top left 100x100 area // Use LK.gui.top (centered horizontally, below top edge) upgradeBtn.x = LK.gui.top.width / 2; upgradeBtn.y = 100 + upgradeBtn.height / 2; // Place leftBtn to the left of upgradeBtn, with a small gap leftBtn.x = upgradeBtn.x - upgradeBtn.width / 2 - leftBtn.width / 2 - 30; leftBtn.y = upgradeBtn.y; // Place workBtn to the right of upgradeBtn, with a small gap workBtn.x = upgradeBtn.x + upgradeBtn.width / 2 + workBtn.width / 2 + 30; workBtn.y = upgradeBtn.y; // Add gold required text under the upgrade button var upgradeCostTxt = new Text2("", { size: 40, fill: 0x222A36, glow: { color: 0xffffff, distance: 8, strength: 2 } }); upgradeCostTxt.anchor.set(0.5, 0); upgradeCostTxt.x = upgradeBtn.x; upgradeCostTxt.y = upgradeBtn.y + upgradeBtn.height / 2 + 10; LK.gui.top.addChild(upgradeCostTxt); LK.gui.top.addChild(leftBtn); LK.gui.top.addChild(upgradeBtn); LK.gui.top.addChild(workBtn); // Spawn enemy button (bottom center) var spawnBtn = LK.getAsset('spawnBtn', { anchorX: 0.5, anchorY: 0.5 }); // Place spawnBtn at bottom center, above the very bottom edge spawnBtn.x = LK.gui.bottom.width / 2; spawnBtn.y = LK.gui.bottom.height - 100 - spawnBtn.height / 2; // Add "find enemy!" text above the spawn button var findEnemyTxt = new Text2("find enemy!", { size: 45, fill: 0x222A36, glow: { color: 0xffffff, distance: 8, strength: 2 } }); findEnemyTxt.anchor.set(0.5, 1); findEnemyTxt.x = spawnBtn.x; findEnemyTxt.y = spawnBtn.y - spawnBtn.height / 2 - 20; LK.gui.bottom.addChild(findEnemyTxt); LK.gui.bottom.addChild(spawnBtn); // Add itemBag image, 10x size, on the left diagonal of spawnBtn so they do not overlap // Set itemBag to width 300px, height 250px, anchor (0.3, 0.20) // Place on the left diagonal of spawnBtn, with a gap so they do not overlap var itemBagWidth = 300; var itemBagHeight = 200; var itemBagAnchorX = 0.3; var itemBagAnchorY = 0.20; var diagonalGap = 40; var diagonalOffset = (spawnBtn.width * (1 - itemBagAnchorX) + itemBagWidth * itemBagAnchorX + diagonalGap) / Math.sqrt(2); var itemBagImg = LK.getAsset('itemBag', { anchorX: itemBagAnchorX, anchorY: itemBagAnchorY, x: spawnBtn.x - diagonalOffset, y: spawnBtn.y - diagonalOffset, width: itemBagWidth, height: itemBagHeight }); LK.gui.bottom.addChild(itemBagImg); // --- Item drop logic on itemBag tap --- itemBagImg.down = function (x, y, obj) { // Animate shrink and grow like other buttons tween.stop(itemBagImg, { scaleX: true, scaleY: true }); tween(itemBagImg, { scaleX: 0.9, scaleY: 0.9 }, { duration: 100, easing: tween.cubicIn, onFinish: function onFinish() { tween(itemBagImg, { scaleX: 1, scaleY: 1 }, { duration: 100, easing: tween.cubicOut, onFinish: function onFinish() { // --- Show 1000x1000 black, 30% transparent window in center --- // Remove previous if exists if (typeof itemBagWindow !== "undefined" && itemBagWindow && itemBagWindow.parent) { itemBagWindow.parent.removeChild(itemBagWindow); itemBagWindow = null; } // Create window container itemBagWindow = new Container(); // Use a box shape for the window background var winWidth = 1000; var winHeight = 1000; var winColor = 0x000000; // black var winAlpha = 0.3; var winBg = LK.getAsset('centerCircle', { width: winWidth, height: winHeight, color: winColor, shape: 'box', anchorX: 0.5, anchorY: 0.5, x: 0, y: 0 }); winBg.alpha = winAlpha; itemBagWindow.addChild(winBg); // Add X close button to top right of window var closeBtnSize = 90; var closeBtn = LK.getAsset('centerCircle', { width: closeBtnSize, height: closeBtnSize, color: 0x222222, shape: 'box', anchorX: 0.5, anchorY: 0.5, x: winWidth / 2 - closeBtnSize / 2 - 20, y: -winHeight / 2 + closeBtnSize / 2 + 20 }); closeBtn.alpha = 0.7; itemBagWindow.addChild(closeBtn); // Add X text on top of closeBtn var closeBtnTxt = new Text2("X", { size: 60, fill: "#fff" }); closeBtnTxt.anchor.set(0.5, 0.5); closeBtnTxt.x = closeBtn.x; closeBtnTxt.y = closeBtn.y; itemBagWindow.addChild(closeBtnTxt); // --- Hide spawnBtn, workBtn, upgradeBtn, leftBtn, and all on-screen texts when X is visible --- spawnBtn.visible = false; workBtn.visible = false; upgradeBtn.visible = false; leftBtn.visible = false; findEnemyTxt.visible = false; upgradeCostTxt.visible = false; heroStatsTxt.visible = false; enemyStatsTxt.visible = false; goldTxt.visible = false; goldBagImg.visible = false; if (workBtnCountdownTxt) workBtnCountdownTxt.visible = false; // Close logic for X button closeBtn.down = function () { if (itemBagWindow && itemBagWindow.parent) { itemBagWindow.parent.removeChild(itemBagWindow); itemBagWindow = null; } // Restore all UI elements spawnBtn.visible = true; workBtn.visible = true; upgradeBtn.visible = true; leftBtn.visible = true; findEnemyTxt.visible = true; upgradeCostTxt.visible = true; heroStatsTxt.visible = true; enemyStatsTxt.visible = true; goldTxt.visible = true; goldBagImg.visible = true; if (workBtnCountdownTxt && workBtnActive === false && workBtnTimeLeft > 0) { workBtnCountdownTxt.visible = true; } }; // Center in game area itemBagWindow.x = 2048 / 2; itemBagWindow.y = 2732 / 2; // Add to game game.addChild(itemBagWindow); // (Removed: close window on tap anywhere on window. Now only X closes the window) // --- Inventory UI inside itemBagWindow --- // Remove any previous inventory UI if (typeof itemBagInventoryUI !== "undefined" && itemBagInventoryUI && itemBagInventoryUI.parent) { itemBagInventoryUI.parent.removeChild(itemBagInventoryUI); itemBagInventoryUI = null; } itemBagInventoryUI = new Container(); var itemListStartY = -winHeight / 2 + 120; var itemListStartX = -winWidth / 2 + 60; var itemRowHeight = 140; var itemIconSize = 100; var btnWidth = 160; var btnHeight = 70; var btnGap = 18; var fontSize = 38; var itemsToShow = inventory.length; if (itemsToShow === 0) { var noItemTxt = new Text2("Envanter boş!", { size: 48, fill: "#fff" }); noItemTxt.anchor.set(0.5, 0.5); noItemTxt.x = 0; noItemTxt.y = 0; itemBagInventoryUI.addChild(noItemTxt); } else { // Build a count of each item in inventory, and track equipped index for each type var itemStacks = []; var itemStackMap = {}; // itemId -> array of {idx, equipped} for (var i = 0; i < inventory.length; i++) { var id = inventory[i]; if (!itemStackMap[id]) itemStackMap[id] = []; // If this is equipped and not already marked, mark as equipped var isEquipped = false; if (equippedItems[id]) { // Only one equipped per type, so only one stack can be equipped var alreadyEquipped = false; for (var s = 0; s < itemStackMap[id].length; s++) { if (itemStackMap[id][s].equipped) alreadyEquipped = true; } if (!alreadyEquipped) isEquipped = true; } itemStackMap[id].push({ idx: i, equipped: isEquipped }); } // Now, for each item type, create a stack for equipped and for each group of unequipped var stackRows = []; for (var id in itemStackMap) { var stack = itemStackMap[id]; // Find equipped var equippedIdx = -1; for (var s = 0; s < stack.length; s++) { if (stack[s].equipped) equippedIdx = stack[s].idx; } if (equippedIdx !== -1) { stackRows.push({ itemId: id, count: 1, equipped: true, indices: [equippedIdx] }); } // Now, group unequipped into stacks (could be more than one stack if equipped is in the middle) var unequippedIndices = []; for (var s = 0; s < stack.length; s++) { if (!stack[s].equipped) unequippedIndices.push(stack[s].idx); } if (unequippedIndices.length > 0) { // Group all unequipped as one stack stackRows.push({ itemId: id, count: unequippedIndices.length, equipped: false, indices: unequippedIndices }); } } // Now, render each stackRow as a separate row in the inventory UI for (var row = 0; row < stackRows.length; row++) { (function (rowIdx) { var stack = stackRows[rowIdx]; var itemId = stack.itemId; var data = itemData[itemId]; var count = stack.count; var isEquipped = stack.equipped; // Icon var icon = LK.getAsset(itemId, { anchorX: 0.5, anchorY: 0.5, x: itemListStartX + itemIconSize / 2, y: itemListStartY + (rowIdx + 1) * itemRowHeight - itemRowHeight + itemIconSize / 2, width: itemIconSize, height: itemIconSize }); itemBagInventoryUI.addChild(icon); // Name and stats, show count and equipped var labelText = data ? data.name : itemId; if (count > 1) labelText += " x" + count; if (isEquipped) labelText += " (Kuşanıldı)"; var label = new Text2(labelText, { size: fontSize, fill: "#fff" }); label.anchor.set(0, 0.5); label.x = icon.x + itemIconSize / 2 + 20; label.y = icon.y; itemBagInventoryUI.addChild(label); // Equip/Remove button (only for equipped or first unequipped stack) var showEquipBtn = !isEquipped && !equippedItems[itemId] || isEquipped; var equipBtn = LK.getAsset('centerCircle', { width: btnWidth, height: btnHeight, color: 0x2a6bde, shape: 'box', anchorX: 0.5, anchorY: 0.5, x: label.x + 340, y: icon.y }); equipBtn.alpha = 0.85; itemBagInventoryUI.addChild(equipBtn); var equipTxt = new Text2(isEquipped ? "Çıkart" : "Kuşan", { size: fontSize, fill: "#fff" }); equipTxt.anchor.set(0.5, 0.5); equipTxt.x = equipBtn.x; equipTxt.y = equipBtn.y; itemBagInventoryUI.addChild(equipTxt); equipBtn.visible = showEquipBtn; equipTxt.visible = showEquipBtn; // Equip/Remove logic equipBtn.down = function () { if (!isEquipped) { // Equip this stack (first unequipped) // Unequip all of this type for (var k in equippedItems) { if (itemData[k] && itemData[k].type === data.type) { equippedItems[k] = false; if (typeof hero.equippedVisuals !== "undefined" && hero.equippedVisuals[k]) { hero.removeChild(hero.equippedVisuals[k]); hero.equippedVisuals[k].destroy(); hero.equippedVisuals[k] = null; } } } equippedItems[itemId] = true; // Show item visual on hero (front) if (typeof hero.equippedVisuals === "undefined") hero.equippedVisuals = {}; if (hero.equippedVisuals[itemId]) { hero.removeChild(hero.equippedVisuals[itemId]); hero.equippedVisuals[itemId].destroy(); hero.equippedVisuals[itemId] = null; } var equipVisual; if (itemId === "shield-1") { equipVisual = LK.getAsset(itemId, { anchorX: 0.5, anchorY: 0.5, x: 240, // Move shield visual even further right on hero's body y: 0, width: 300, height: 698 }); } else { equipVisual = LK.getAsset(itemId, { anchorX: 0.5, anchorY: 0.5, x: 90, y: 0, width: 320, height: 320 }); } hero.addChild(equipVisual); hero.equippedVisuals[itemId] = equipVisual; // Shield-1 barrier logic if (itemId === "shield-1") { heroShield1Barrier = 250; heroShield1BarrierMax = 250; } var stats = getStatsForLevel(heroLevel, "hero"); hero.currentHp = stats.hp; updateHeroStatsDisplay(); if (itemBagWindow && itemBagWindow.parent) { itemBagWindow.parent.removeChild(itemBagWindow); itemBagWindow = null; } itemBagImg.down(); } else { // Remove (Çıkart) equippedItems[itemId] = false; if (typeof hero.equippedVisuals !== "undefined" && hero.equippedVisuals[itemId]) { hero.removeChild(hero.equippedVisuals[itemId]); hero.equippedVisuals[itemId].destroy(); hero.equippedVisuals[itemId] = null; } if (itemId === "shield-1") { heroShield1Barrier = 0; heroShield1BarrierMax = 0; } var stats = getStatsForLevel(heroLevel, "hero"); hero.currentHp = stats.hp; updateHeroStatsDisplay(); if (itemBagWindow && itemBagWindow.parent) { itemBagWindow.parent.removeChild(itemBagWindow); itemBagWindow = null; } itemBagImg.down(); } }; // Sell button var sellBtn = LK.getAsset('centerCircle', { width: btnWidth, height: btnHeight, color: 0x8B4513, shape: 'box', anchorX: 0.5, anchorY: 0.5, x: equipBtn.x + btnWidth + btnGap, y: icon.y }); sellBtn.alpha = 0.85; itemBagInventoryUI.addChild(sellBtn); var sellTxt = new Text2("Sat (" + (data ? data.sellPrice : 1) + ")", { size: fontSize, fill: "#fff" }); sellTxt.anchor.set(0.5, 0.5); sellTxt.x = sellBtn.x; sellTxt.y = sellBtn.y; itemBagInventoryUI.addChild(sellTxt); // Sell logic sellBtn.down = function () { // If this stack is equipped, and only one exists, prevent selling if (isEquipped && count === 1) { tween(sellBtn, { scaleX: 1.15, scaleY: 1.15, tint: 0xff4444 }, { duration: 120, onFinish: function onFinish() { tween(sellBtn, { scaleX: 1, scaleY: 1, tint: 0x8B4513 }, { duration: 120 }); } }); return; } // Remove one from inventory (from this stack) var removedIdx = -1; for (var j = 0; j < stack.indices.length; j++) { var idx = stack.indices[j]; // If equipped, skip if this is the equipped one if (isEquipped && count === 1) continue; removedIdx = idx; break; } if (removedIdx === -1) { // Defensive: fallback to remove first found for (var j = 0; j < inventory.length; j++) { if (inventory[j] === itemId && (!isEquipped || isEquipped && count > 1)) { removedIdx = j; break; } } } if (removedIdx !== -1) { inventory.splice(removedIdx, 1); } // If equipped and now zero remain, unequip var stillHas = false; for (var j = 0; j < inventory.length; j++) { if (inventory[j] === itemId) stillHas = true; } if (isEquipped && !stillHas) { equippedItems[itemId] = false; var stats = getStatsForLevel(heroLevel, "hero"); hero.currentHp = stats.hp; updateHeroStatsDisplay(); } // Add gold goldAmount += data ? data.sellPrice : 1; updateGoldDisplay(); // Animate gold to gold counter var goldDisplayGlobal = LK.gui.topRight.toGlobal({ x: goldTxt.x, y: goldTxt.y }); var goldDisplayGamePos = game.toLocal(goldDisplayGlobal); var goldAnim = LK.getAsset('gold', { anchorX: 0.5, anchorY: 0.5, x: sellBtn.x + itemBagWindow.x, y: sellBtn.y + itemBagWindow.y, width: 80, height: 54 }); game.addChild(goldAnim); tween(goldAnim, { x: goldDisplayGamePos.x, y: goldDisplayGamePos.y, scaleX: 0.3, scaleY: 0.3, alpha: 0 }, { duration: 420, easing: tween.cubicIn, onFinish: function onFinish() { goldAnim.destroy(); } }); // Refresh inventory UI if (itemBagWindow && itemBagWindow.parent) { itemBagWindow.parent.removeChild(itemBagWindow); itemBagWindow = null; } itemBagImg.down(); }; })(row); } } itemBagInventoryUI.x = 0; itemBagInventoryUI.y = 0; itemBagWindow.addChild(itemBagInventoryUI); // --- (Keep original drop animation for demo) --- var dropX = itemBagImg.x; var dropY = 0 - itemBagHeight; // Start above screen var item = LK.getAsset('gold', { anchorX: 0.5, anchorY: 0.5, x: dropX, y: dropY, width: 150, height: 102 }); game.addChild(item); // Animate drop to itemBag tween(item, { x: itemBagImg.x, y: itemBagImg.y }, { duration: 600, easing: tween.bounceOut, onFinish: function onFinish() { // Optionally: fade out and destroy after reaching itemBag tween(item, { alpha: 0 }, { duration: 250, onFinish: function onFinish() { item.destroy(); } }); } }); } }); } }); }; // --- Helper Functions --- function updateGoldDisplay() { goldTxt.setText(goldAmount); } function updateUpgradeDisplay() { // Show gold required to upgrade under the upgrade button if (typeof upgradeCostTxt !== "undefined") { var nextUpgradeCost = heroLevel * 5; upgradeCostTxt.setText("Gold required: " + nextUpgradeCost); } } // Update hero stats display function updateHeroStatsDisplay() { var stats = getStatsForLevel(heroLevel, "hero"); var hpDisplay = typeof hero.currentHp === "number" ? Math.max(0, Math.round(hero.currentHp)) + " / " + stats.hp : stats.hp; var barrierDisplay = ""; if (equippedItems && equippedItems["shield-1"] && heroShield1Barrier > 0) { barrierDisplay = " +" + heroShield1Barrier; } heroStatsTxt.setText("Hero\n" + "Level: " + heroLevel + "\n" + "Health: " + hpDisplay + barrierDisplay + "\n" + "Attack: " + stats.atk + "\n" + "Atk Spd: " + stats.atkSpd); } // Update enemy stats display function updateEnemyStatsDisplay() { if (currentEnemy && currentEnemy.isAlive) { var enemyLevel = currentEnemy.level || heroLevel; var stats = getStatsForLevel(enemyLevel, "enemy"); var hpDisplay = typeof currentEnemy.hp === "number" ? Math.max(0, Math.round(currentEnemy.hp)) + " / " + stats.hp : stats.hp; enemyStatsTxt.setText("Enemy\n" + "Level: " + enemyLevel + "\n" + "Health: " + hpDisplay + "\n" + "Attack: " + currentEnemy.attack + "\n" + "Atk Spd: " + currentEnemy.attackSpeed); } else { enemyStatsTxt.setText("Enemy\n-"); } } // --- Game Logic --- // Spawn enemy logic // Enemy stat table for levels 1-10 (fixed stats) var enemyStatsByLevel = [ // Level 1 { hp: 60, atk: 10, atkSpd: 2 }, // Level 2 { hp: 95, atk: 14, atkSpd: 3 }, // Level 3 { hp: 130, atk: 18, atkSpd: 4 }, // Level 4 { hp: 170, atk: 23, atkSpd: 4 }, // Level 5 { hp: 215, atk: 27, atkSpd: 5 }, // Level 6 { hp: 265, atk: 32, atkSpd: 6 }, // Level 7 { hp: 320, atk: 38, atkSpd: 6 }, // Level 8 { hp: 380, atk: 45, atkSpd: 7 }, // Level 9 { hp: 445, atk: 53, atkSpd: 8 }, // Level 10 { hp: 515, atk: 62, atkSpd: 9 }]; // --- Stat scaling logic for hero and enemy after level 10 --- // Store hero stat growth per level (compounded) and enemy stat growth per level (linear from level 10 base) var heroStatGrowth = { hp: [enemyStatsByLevel[9].hp], atk: [enemyStatsByLevel[9].atk], atkSpd: [enemyStatsByLevel[9].atkSpd] }; var enemyStatGrowth = { hp: [enemyStatsByLevel[9].hp], atk: [enemyStatsByLevel[9].atk], atkSpd: [enemyStatsByLevel[9].atkSpd] }; // Store enemy stat percent increases per level (for linear scaling) var enemyStatPercents = { hp: [], atk: [], atkSpd: [] }; // Store hero stat percent increases per level (for compounded scaling) var heroStatPercents = { hp: [], atk: [], atkSpd: [] }; // Helper to get random percent between 5% and 20% function randomPercent() { return 0.05 + Math.random() * 0.15; } // Precompute stat growth up to a reasonable max level (e.g. 100) function ensureStatGrowthUpTo(level) { var maxComputed = heroStatGrowth.hp.length + 9; // since index 0 is level 10 for (var lvl = maxComputed + 1; lvl <= level; lvl++) { // HERO: compounded var prevHeroHp = heroStatGrowth.hp[heroStatGrowth.hp.length - 1]; var prevHeroAtk = heroStatGrowth.atk[heroStatGrowth.atk.length - 1]; var prevHeroAtkSpd = heroStatGrowth.atkSpd[heroStatGrowth.atkSpd.length - 1]; var heroHpPct = randomPercent(); var heroAtkPct = randomPercent(); // After level 15, hero attack speed no longer increases var heroAtkSpdPct = lvl > 15 ? 0 : randomPercent(); heroStatPercents.hp.push(heroHpPct); heroStatPercents.atk.push(heroAtkPct); heroStatPercents.atkSpd.push(heroAtkSpdPct); heroStatGrowth.hp.push(Math.round(prevHeroHp * (1 + heroHpPct))); heroStatGrowth.atk.push(Math.round(prevHeroAtk * (1 + heroAtkPct))); heroStatGrowth.atkSpd.push(Math.round(prevHeroAtkSpd * (1 + heroAtkSpdPct))); // ENEMY: linear from level 10 base var baseHp = enemyStatsByLevel[9].hp; var baseAtk = enemyStatsByLevel[9].atk; var baseAtkSpd = enemyStatsByLevel[9].atkSpd; var enemyHpPct = randomPercent(); var enemyAtkPct = randomPercent(); // After level 15, enemy attack speed no longer increases var enemyAtkSpdPct = lvl > 15 ? 0 : randomPercent(); enemyStatPercents.hp.push(enemyHpPct); enemyStatPercents.atk.push(enemyAtkPct); enemyStatPercents.atkSpd.push(enemyAtkSpdPct); // For linear, sum all previous percent increases var totalHpPct = 0; var totalAtkPct = 0; var totalAtkSpdPct = 0; for (var i = 0; i < enemyStatPercents.hp.length; i++) totalHpPct += enemyStatPercents.hp[i]; for (var i = 0; i < enemyStatPercents.atk.length; i++) totalAtkPct += enemyStatPercents.atk[i]; for (var i = 0; i < enemyStatPercents.atkSpd.length; i++) totalAtkSpdPct += enemyStatPercents.atkSpd[i]; // After level 20, enemy health increases by an additional 50% per level var extraHpMultiplier = 1; if (lvl > 20) { // For each level above 20, multiply by 1.5 for each extra level extraHpMultiplier = Math.pow(1.5, lvl - 20); } enemyStatGrowth.hp.push(Math.round(baseHp * (1 + totalHpPct) * extraHpMultiplier)); enemyStatGrowth.atk.push(Math.round(baseAtk * (1 + totalAtkPct))); enemyStatGrowth.atkSpd.push(Math.round(baseAtkSpd * (1 + totalAtkSpdPct))); } } // Returns stats for a given level and type ('hero' or 'enemy') function getStatsForLevel(level, type) { if (level <= 10) { var idx = Math.max(0, Math.min(enemyStatsByLevel.length - 1, level - 1)); var stats = enemyStatsByLevel[idx]; return { hp: stats.hp, atk: stats.atk, atkSpd: stats.atkSpd }; } ensureStatGrowthUpTo(level); var idx = level - 10; if (type === "hero") { // Base stats var baseHp = heroStatGrowth.hp[idx]; var baseAtk = heroStatGrowth.atk[idx]; var baseAtkSpd = heroStatGrowth.atkSpd[idx]; // Apply shield-1 effects if equipped if (equippedItems && equippedItems["shield-1"]) { baseHp += itemData["shield-1"].bonusHp; baseAtkSpd = Math.max(1, baseAtkSpd - itemData["shield-1"].atkSpdPenalty); } return { hp: baseHp, atk: baseAtk, atkSpd: baseAtkSpd }; } else { return { hp: enemyStatGrowth.hp[idx], atk: enemyStatGrowth.atk[idx], atkSpd: enemyStatGrowth.atkSpd[idx] }; } } // For backward compatibility, keep getEnemyStatsForLevel for hero stats (used in refill, etc) function getEnemyStatsForLevel(level) { return getStatsForLevel(level, "hero"); } function spawnEnemy() { if (currentEnemy && currentEnemy.isAlive) return; // Only one at a time if (hero.healthRefilling) return; // Don't allow spawn while refilling var enemy = new Enemy(); // Place enemy on the far right, vertically aligned with hero enemy.x = 2048 - 200; // 200px from the right edge, matching hero's 200px from left enemy.y = hero.y; // Determine enemy level: always one of heroLevel-1, heroLevel, heroLevel+1, or heroLevel+2 var possibleLevels = [Math.max(1, heroLevel - 1), heroLevel, heroLevel + 1, heroLevel + 2]; // Remove duplicates and clamp to at least 1 var uniqueLevels = []; for (var i = 0; i < possibleLevels.length; i++) { var lvl = Math.max(1, possibleLevels[i]); if (uniqueLevels.indexOf(lvl) === -1) uniqueLevels.push(lvl); } // Randomly pick one var enemyLevel = uniqueLevels[Math.floor(Math.random() * uniqueLevels.length)]; // Clamp enemyLevel to valid range for stats table enemyLevel = Math.max(1, Math.min(enemyStatsByLevel.length + heroStatGrowth.hp.length, enemyLevel)); // Get stats for this level (enemy uses linear scaling after level 10) var stats = getStatsForLevel(enemyLevel, "enemy"); enemy.hp = stats.hp; enemy.attack = stats.atk; enemy.attackSpeed = stats.atkSpd; enemy.isAlive = true; enemy.spawnAnim(); game.addChild(enemy); currentEnemy = enemy; // Store the enemy's level for display currentEnemy.level = enemyLevel; updateEnemyStatsDisplay(); // --- Start auto-fight timers --- if (typeof heroAutoAttackTimer !== "undefined" && heroAutoAttackTimer) { LK.clearInterval(heroAutoAttackTimer); heroAutoAttackTimer = null; } if (typeof enemyAutoAttackTimer !== "undefined" && enemyAutoAttackTimer) { LK.clearInterval(enemyAutoAttackTimer); enemyAutoAttackTimer = null; } // Get hero stats for this level (hero uses compounded scaling after level 10) var heroStats = getStatsForLevel(heroLevel, "hero"); hero.currentHp = heroStats.hp; hero.attack = heroStats.atk; hero.attackSpeed = heroStats.atkSpd; // Hero attacks enemy heroAutoAttackTimer = LK.setInterval(function () { if (!currentEnemy || !currentEnemy.isAlive) { LK.clearInterval(heroAutoAttackTimer); heroAutoAttackTimer = null; return; } // If one-shot mode, instantly defeat enemy if (heroOneShotEnemies) { currentEnemy.hp = 0; } else { currentEnemy.hp -= hero.attack; } // Flash enemy if (currentEnemy) { tween(currentEnemy, { tint: 0xffffff }, { duration: 60, onFinish: function onFinish() { if (currentEnemy) { tween(currentEnemy, { tint: 0x2a6bde }, { duration: 60 }); } } }); } updateEnemyStatsDisplay(); if (currentEnemy.hp <= 0) { defeatEnemy(); LK.clearInterval(heroAutoAttackTimer); heroAutoAttackTimer = null; LK.clearInterval(enemyAutoAttackTimer); enemyAutoAttackTimer = null; } }, 1000 / hero.attackSpeed); // Enemy attacks hero enemyAutoAttackTimer = LK.setInterval(function () { if (!currentEnemy || !currentEnemy.isAlive) { LK.clearInterval(enemyAutoAttackTimer); enemyAutoAttackTimer = null; return; } if (typeof hero.currentHp !== "number") { // Defensive: ensure hero.currentHp is set var hStats = getEnemyStatsForLevel(heroLevel); hero.currentHp = hStats.hp; } if (!heroIsImmortal) { // --- Shield-1 barrier logic: block damage with barrier first --- if (equippedItems && equippedItems["shield-1"] && heroShield1Barrier > 0) { var dmg = currentEnemy.attack; if (heroShield1Barrier >= dmg) { heroShield1Barrier -= dmg; dmg = 0; } else { dmg -= heroShield1Barrier; heroShield1Barrier = 0; } if (dmg > 0) { hero.currentHp -= dmg; } } else { hero.currentHp -= currentEnemy.attack; } // Flash hero tween(hero, { tint: 0xffffff }, { duration: 60, onFinish: function onFinish() { tween(hero, { tint: 0xd83318 }, { duration: 60 }); } }); updateHeroStatsDisplay(); if (hero.currentHp <= 0) { // Hero defeated, stop fighting hero.currentHp = 0; updateHeroStatsDisplay(); // Optionally, you can add defeat logic here (e.g. show game over) LK.clearInterval(heroAutoAttackTimer); heroAutoAttackTimer = null; LK.clearInterval(enemyAutoAttackTimer); enemyAutoAttackTimer = null; // Start health refill (handled in update loop) hero.healthRefilling = false; // Will be set to true in update loop } } else { // If immortal, keep HP at max and flash gold var stats = getStatsForLevel(heroLevel, "hero"); hero.currentHp = stats.hp; updateHeroStatsDisplay(); tween(hero, { tint: 0xFFD700 }, { duration: 60, onFinish: function onFinish() { tween(hero, { tint: 0xffffff }, { duration: 60 }); } }); } }, 1000 / currentEnemy.attackSpeed); } // Defeat enemy logic function defeatEnemy() { if (!currentEnemy || !currentEnemy.isAlive) return; currentEnemy.isAlive = false; // Stop auto-fight timers if (typeof heroAutoAttackTimer !== "undefined" && heroAutoAttackTimer) { LK.clearInterval(heroAutoAttackTimer); heroAutoAttackTimer = null; } if (typeof enemyAutoAttackTimer !== "undefined" && enemyAutoAttackTimer) { LK.clearInterval(enemyAutoAttackTimer); enemyAutoAttackTimer = null; } currentEnemy.defeatAnim(function () { if (currentEnemy) { // --- Shield-1 drop logic --- // Only drop for enemy levels 1-10 if (typeof currentEnemy.level !== "undefined" && currentEnemy.level >= 1 && currentEnemy.level <= 10) { // 5% per level, capped at 50% for level 10 var shieldDropChance = currentEnemy.level * 0.05; if (Math.random() < shieldDropChance) { // Drop shield-1 at enemy's position var shieldAsset = LK.getAsset('shield-1', { anchorX: 0.5, anchorY: 0.5, x: currentEnemy.x, y: currentEnemy.y }); game.addChild(shieldAsset); // Animate drop: move to itemBag position and shrink/fade out // Get itemBag position in game coordinates var itemBagGlobal = LK.gui.bottom.toGlobal({ x: itemBagImg.x, y: itemBagImg.y }); var itemBagGamePos = game.toLocal(itemBagGlobal); tween(shieldAsset, { x: itemBagGamePos.x, y: itemBagGamePos.y, scaleX: 0.3, scaleY: 0.3, alpha: 0.2 }, { duration: 700, easing: tween.cubicIn, onFinish: function onFinish() { shieldAsset.destroy(); // Add to inventory only (do not auto-equip) inventory.push("shield-1"); } }); } } currentEnemy.destroy(); currentEnemy = null; updateEnemyStatsDisplay(); // If shield-1 is equipped, restore hero HP to new max after enemy defeat if (equippedItems["shield-1"]) { heroShield1Barrier = 250; heroShield1BarrierMax = 250; var stats = getStatsForLevel(heroLevel, "hero"); hero.currentHp = stats.hp; updateHeroStatsDisplay(); } } // --- spawnBtn rotation logic on enemy defeat --- // If hero HP is full, rotate 45deg right, else 90deg left var heroStats = getStatsForLevel(heroLevel, "hero"); if (typeof hero.currentHp === "number" && hero.currentHp >= heroStats.hp) { // Full health: rotate 45deg right spawnBtnRotationQueue.push({ angle: Math.PI / 4 }); } else { // Not full: rotate 90deg left spawnBtnRotationQueue.push({ angle: -Math.PI / 2, onFinish: function onFinish() { // After 90deg left, if hero HP is still not full and no enemy, resume right rotation if ((!currentEnemy || !currentEnemy.isAlive) && typeof hero.currentHp === "number" && hero.currentHp < getStatsForLevel(heroLevel, "hero").hp) { if (!spawnBtn._rotatingWhileNotFull) { spawnBtn._rotatingWhileNotFull = true; // Start continuous right rotation (1 full spin per 1.2s) var _rotateRightLoop = function rotateRightLoop() { if (!spawnBtn._rotatingWhileNotFull) return; var startRot = spawnBtn.rotation; var endRot = startRot + Math.PI * 2; tween(spawnBtn, { rotation: endRot }, { duration: 1200, easing: tween.linear, onFinish: function onFinish() { if (spawnBtn._rotatingWhileNotFull && (!currentEnemy || !currentEnemy.isAlive)) { _rotateRightLoop(); } } }); }; tween.stop(spawnBtn, { rotation: true }); _rotateRightLoop(); } } } }); } processSpawnBtnRotationQueue(); // Start hero health refill after any battle (at same refill speed as on defeat) // If hero died (currentHp <= 0), double the refill duration if (typeof hero.currentHp === "number" && hero.currentHp < getStatsForLevel(heroLevel, "hero").hp && !hero.healthRefilling) { hero.healthRefilling = true; hero.refillStartTime = Date.now(); var stats = getStatsForLevel(heroLevel, "hero"); hero.refillFromHp = hero.currentHp; hero.refillToHp = stats.hp; // Set refill duration to 1/5th speed (5x slower), or 1/10th (10x slower) if hero died var baseDuration = 1000; // original duration if (hero.currentHp <= 0) { hero.refillDuration = baseDuration * 10; // 10x slower if died } else { hero.refillDuration = baseDuration * 5; // 5x slower otherwise } } }); // --- Gold drop amount table per level --- var goldDropByLevel = [{ min: 1, max: 5 }, // Level 1 { min: 3, max: 8 }, // Level 2 { min: 5, max: 12 }, // Level 3 { min: 8, max: 16 }, // Level 4 { min: 12, max: 20 }, // Level 5 { min: 15, max: 25 }, // Level 6 { min: 20, max: 32 }, // Level 7 { min: 25, max: 40 }, // Level 8 { min: 30, max: 48 }, // Level 9 { min: 35, max: 60 } // Level 10 ]; // Determine gold drop amount for this level var goldDropStats = goldDropByLevel[Math.max(0, Math.min(heroLevel - 1, goldDropByLevel.length - 1))]; var goldDropAmount = Math.floor(Math.random() * (goldDropStats.max - goldDropStats.min + 1)) + goldDropStats.min; // Drop gold at the far right (where enemy was) // Animate and auto-collect gold after enemy defeat // Calculate the gold display position in game coordinates (top right, where goldTxt is) var goldDisplayGlobal = LK.gui.topRight.toGlobal({ x: goldTxt.x, y: goldTxt.y }); var goldDisplayGamePos = game.toLocal(goldDisplayGlobal); for (var i = 0; i < goldDropAmount; i++) { var gold = new Gold(); gold.x = 2048 - 200; gold.y = hero.y; gold.scaleX = 1; gold.scaleY = 1; gold.alpha = 1; game.addChild(gold); golds.push(gold); // Drop to random y near enemy var dropY = gold.y + (Math.random() * 120 - 60); (function (goldObj, idx) { goldObj.dropAnim(goldObj.x, dropY, function () { // Stagger collection for nice effect LK.setTimeout(function () { // Animate to gold display and collect goldObj.collectAnim(goldDisplayGamePos.x, goldDisplayGamePos.y, function () { goldAmount += 1; updateGoldDisplay(); goldObj.destroy(); }); }, 80 * idx); }); })(gold, i); } // --- Shield-1 drop logic --- // Only drop for enemy levels 1-10 if (typeof enemyLevel !== "undefined" && enemyLevel >= 1 && enemyLevel <= 10) { // 5% per level, capped at 50% for level 10 var shieldDropChance = enemyLevel * 0.05; if (Math.random() < shieldDropChance) { // Drop shield-1 at enemy's position var shieldAsset = LK.getAsset('shield-1', { anchorX: 0.5, anchorY: 0.5, x: 2048 - 200, y: hero.y }); game.addChild(shieldAsset); // Animate drop (fall down a bit, then fade out) var dropTargetY = shieldAsset.y + 180 + (Math.random() * 40 - 20); tween(shieldAsset, { y: dropTargetY }, { duration: 400, easing: tween.bounceOut, onFinish: function onFinish() { // After a short delay, fade out and destroy LK.setTimeout(function () { tween(shieldAsset, { alpha: 0 }, { duration: 350, onFinish: function onFinish() { shieldAsset.destroy(); } }); }, 900); } }); } } } // --- Shield-1 drop logic --- // Only drop for enemy levels 1-10 if (typeof enemyLevel !== "undefined" && enemyLevel >= 1 && enemyLevel <= 10) { // 5% per level, capped at 50% for level 10 var shieldDropChance = enemyLevel * 0.05; if (Math.random() < shieldDropChance) { // Drop shield-1 at enemy's position var shieldAsset = LK.getAsset('shield-1', { anchorX: 0.5, anchorY: 0.5, x: 2048 - 200, y: hero.y }); game.addChild(shieldAsset); // Animate drop (fall down a bit, then fade out) var dropTargetY = shieldAsset.y + 180 + (Math.random() * 40 - 20); tween(shieldAsset, { y: dropTargetY }, { duration: 400, easing: tween.bounceOut, onFinish: function onFinish() { // After a short delay, fade out and destroy LK.setTimeout(function () { tween(shieldAsset, { alpha: 0 }, { duration: 350, onFinish: function onFinish() { shieldAsset.destroy(); } }); }, 900); } }); } } // Collect gold logic function collectGold(gold) { // Animate to gold display var guiGoldPos = LK.gui.topRight.toLocal(gold.toGlobal({ x: 0, y: 0 })); goldAmount += 1; updateGoldDisplay(); gold.collectAnim(guiGoldPos.x, guiGoldPos.y, function () { gold.destroy(); }); } // Upgrade logic function upgradeHero() { var upgradeCost = heroLevel * 5; if (goldAmount < upgradeCost) { // Flash gold text red tween(goldTxt, { tint: 0xff4444 }, { duration: 120, onFinish: function onFinish() { tween(goldTxt, { tint: 0xFFE066 }, { duration: 120 }); } }); return; } goldAmount -= upgradeCost; heroLevel += 1; hero.level = heroLevel; // Refill hero health to full on level up var stats = getStatsForLevel(heroLevel, "hero"); hero.currentHp = stats.hp; hero.healthRefilling = false; updateGoldDisplay(); updateUpgradeDisplay(); updateHeroStatsDisplay(); updateEnemyStatsDisplay(); hero.flashUpgrade(); } // --- Event Handlers --- // Spawn button tap // --- spawnBtn rotation queue state --- var spawnBtnRotationQueue = []; var spawnBtnIsRotating = false; function processSpawnBtnRotationQueue() { if (spawnBtnIsRotating || spawnBtnRotationQueue.length === 0) return; spawnBtnIsRotating = true; var next = spawnBtnRotationQueue.shift(); var targetRotation = spawnBtn.rotation + next.angle; tween(spawnBtn, { rotation: targetRotation }, { duration: 180, easing: tween.cubicInOut, onFinish: function onFinish() { spawnBtn.rotation = targetRotation; spawnBtnIsRotating = false; if (typeof next.onFinish === "function") next.onFinish(); // Process next in queue processSpawnBtnRotationQueue(); } }); } spawnBtn.down = function (x, y, obj) { // Animate shrink tween.stop(spawnBtn, { scaleX: true, scaleY: true }); tween(spawnBtn, { scaleX: 0.9, scaleY: 0.9 }, { duration: 100, easing: tween.cubicIn, onFinish: function onFinish() { tween(spawnBtn, { scaleX: 1, scaleY: 1 }, { duration: 100, easing: tween.cubicOut, onFinish: function onFinish() { // After animation, trigger action // Queue 45deg right rotation spawnBtnRotationQueue.push({ angle: Math.PI / 4 }); processSpawnBtnRotationQueue(); spawnEnemy(); } }); } }); }; // Enemy tap (defeat) function onEnemyDown(x, y, obj) { if (!currentEnemy || !currentEnemy.isAlive) return; currentEnemy.hp -= 1; // Flash enemy tween(currentEnemy, { tint: 0xffffff }, { duration: 60, onFinish: function onFinish() { tween(currentEnemy, { tint: 0x2a6bde }, { duration: 60 }); } }); if (currentEnemy.hp <= 0) { defeatEnemy(); } } // Gold tap (collect) function onGoldDown(x, y, obj) { for (var i = golds.length - 1; i >= 0; i--) { var gold = golds[i]; if (gold && gold.containsPoint && gold.containsPoint({ x: x, y: y })) { collectGold(gold); golds.splice(i, 1); break; } } } // Upgrade button tap upgradeBtn.down = function (x, y, obj) { // Animate shrink tween.stop(upgradeBtn, { scaleX: true, scaleY: true }); tween(upgradeBtn, { scaleX: 0.9, scaleY: 0.9 }, { duration: 100, easing: tween.cubicIn, onFinish: function onFinish() { tween(upgradeBtn, { scaleX: 1, scaleY: 1 }, { duration: 100, easing: tween.cubicOut, onFinish: function onFinish() { // After animation, trigger action upgradeHero(); } }); } }); }; // Work button tap workBtn.down = function (x, y, obj) { if (!workBtnActive) return; // Prevent workBtn press if hero HP is not full if (typeof hero.currentHp === "number" && hero.currentHp < getStatsForLevel(heroLevel, "hero").hp) return; // Animate shrink tween.stop(workBtn, { scaleX: true, scaleY: true }); tween(workBtn, { scaleX: 0.9, scaleY: 0.9 }, { duration: 100, easing: tween.cubicIn, onFinish: function onFinish() { tween(workBtn, { scaleX: 1, scaleY: 1 }, { duration: 100, easing: tween.cubicOut, onFinish: function onFinish() { // After animation, trigger action // Calculate duration: let duration = Math.max(10000, ((level ** 1.2) * 60000) / (attackSpeed * attack)); var stats = getStatsForLevel(heroLevel, "hero"); var denominator = stats.atkSpd * stats.atk; var duration = 10; // Defensive minimum in seconds if (Number.isFinite(denominator) && denominator > 0) { duration = Math.max(10000, Math.pow(heroLevel, 1.2) * 60000 / denominator) / 1000; // ms to seconds } // Multiply duration by heroLevel (time level) duration = duration * heroLevel; workBtnActive = false; workBtnDuration = duration; workBtnTimeLeft = duration; setSpawnBtnEnabled(false); showWorkBtnCountdown(workBtnTimeLeft); // Start timer to update countdown if (workBtnTimer) { LK.clearInterval(workBtnTimer); workBtnTimer = null; } // Start rotation tween for workBtn at 20% of previous speed tween.stop(workBtn, { rotation: true }); workBtn.rotation = 0; // Calculate totalRotations for 20% speed (i.e., 1/5th the previous speed, so 1/5th the number of spins) var baseTotalRotations = 2 + Math.floor(workBtnDuration); var slowTotalRotations = Math.max(1, Math.round(baseTotalRotations * 0.2)); // at least 1 full spin tween(workBtn, { rotation: Math.PI * 2 * slowTotalRotations }, { duration: workBtnDuration * 1000, easing: tween.linear, onFinish: function onFinish() { workBtn.rotation = 0; // reset rotation to 0 for next use } }); workBtnTimer = LK.setInterval(function () { workBtnTimeLeft -= 0.1; if (workBtnTimeLeft < 0) workBtnTimeLeft = 0; showWorkBtnCountdown(workBtnTimeLeft); if (workBtnTimeLeft <= 0) { // Timer done LK.clearInterval(workBtnTimer); workBtnTimer = null; workBtnActive = true; setSpawnBtnEnabled(true); hideWorkBtnCountdown(); // Stop rotation tween and reset rotation tween.stop(workBtn, { rotation: true }); workBtn.rotation = 0; // Drop gold: (main character's level * attack speed + attack / 2) / random(1-5) var stats = getStatsForLevel(heroLevel, "hero"); var divisor = Math.floor(Math.random() * 5) + 1; var goldVal = heroLevel * stats.atkSpd + stats.atk / 2; var goldDrop = Math.max(1, Math.floor(goldVal / divisor)); // Calculate gold display position in game coordinates (top right, where goldTxt is) var goldDisplayGlobal = LK.gui.topRight.toGlobal({ x: goldTxt.x, y: goldTxt.y }); var goldDisplayGamePos = game.toLocal(goldDisplayGlobal); // Spawn gold under hero and animate to gold display for (var i = 0; i < goldDrop; i++) { var gold = new Gold(); gold.x = hero.x; gold.y = hero.y + hero.height / 2 + 60 + (Math.random() * 40 - 20); gold.scaleX = 1; gold.scaleY = 1; gold.alpha = 1; game.addChild(gold); golds.push(gold); // Animate to gold display (function (goldObj, idx) { // Retreat: move down a bit, then animate to gold display var retreatY = goldObj.y + 80 + (Math.random() * 30 - 15); goldObj.dropAnim(goldObj.x, retreatY, function () { LK.setTimeout(function () { goldObj.collectAnim(goldDisplayGamePos.x, goldDisplayGamePos.y, function () { goldAmount += 1; updateGoldDisplay(); goldObj.destroy(); }); }, 80 * idx); }); })(gold, i); } } }, 100); } }); } }); }; // --- Attach event handlers to game --- game.down = function (x, y, obj) { // Check if tap is on enemy if (currentEnemy && currentEnemy.isAlive && currentEnemy.containsPoint && currentEnemy.containsPoint({ x: x, y: y })) { onEnemyDown(x, y, obj); return; } // Check if tap is on any gold for (var i = golds.length - 1; i >= 0; i--) { var gold = golds[i]; if (gold && gold.containsPoint && gold.containsPoint({ x: x, y: y })) { collectGold(gold); golds.splice(i, 1); return; } } // (Buttons handled by their own .down) }; // --- Game update loop --- game.update = function () { // Remove golds that are invisible for (var i = golds.length - 1; i >= 0; i--) { var gold = golds[i]; if (gold.alpha <= 0.01) { gold.destroy(); golds.splice(i, 1); } } // --- Hero health refill logic --- if (typeof hero.healthRefilling === "undefined") hero.healthRefilling = false; if (typeof hero.refillStartTime === "undefined") hero.refillStartTime = 0; if (typeof hero.refillDuration === "undefined") hero.refillDuration = 5000; // Default, will be set below if (typeof hero.refillFromHp === "undefined") hero.refillFromHp = 0; if (typeof hero.refillToHp === "undefined") hero.refillToHp = 0; if (typeof hero.currentHp === "number" && hero.currentHp <= 0 && !hero.healthRefilling) { // Start refill hero.healthRefilling = true; hero.refillStartTime = Date.now(); var stats = getStatsForLevel(heroLevel, "hero"); hero.refillFromHp = 0; hero.refillToHp = stats.hp; // Set refill duration to 1/5th speed (5x slower) hero.refillDuration = 5000; // fallback var baseDuration = 1000; // original duration if (hero.currentHp <= 0) { hero.refillDuration = baseDuration * 10; // 10x slower if died } else { hero.refillDuration = baseDuration * 5; // 5x slower otherwise } // Destroy enemy immediately (so a new one can only be summoned after refill) if (currentEnemy && currentEnemy.isAlive) { currentEnemy.isAlive = false; currentEnemy.defeatAnim(function () { if (currentEnemy) { currentEnemy.destroy(); currentEnemy = null; updateEnemyStatsDisplay(); } }); } } if (hero.healthRefilling) { var now = Date.now(); var elapsed = now - hero.refillStartTime; var t = Math.min(1, elapsed / hero.refillDuration); var stats = getStatsForLevel(heroLevel, "hero"); hero.currentHp = Math.round(hero.refillFromHp + (hero.refillToHp - hero.refillFromHp) * t); if (t >= 1) { hero.currentHp = stats.hp; hero.healthRefilling = false; // After refill, if shield-1 is equipped, restore barrier to max if (equippedItems && equippedItems["shield-1"]) { heroShield1Barrier = 250; heroShield1BarrierMax = 250; } } } // Prevent spawnBtn and workBtn from being pressed unless hero HP is full if (typeof hero.currentHp === "number" && hero.currentHp < getStatsForLevel(heroLevel, "hero").hp) { setSpawnBtnEnabled(false); // Disable workBtn and make it semi-transparent workBtn.alpha = 0.5; workBtn.interactive = false; workBtn.buttonMode = false; // --- Rotate spawnBtn to the right while hero HP is not full, but only if NO enemy is alive --- if (!spawnBtn._rotatingWhileNotFull && (!currentEnemy || !currentEnemy.isAlive)) { var _rotateRightLoop = function rotateRightLoop() { if (!spawnBtn._rotatingWhileNotFull) return; var startRot = spawnBtn.rotation; var endRot = startRot + Math.PI * 2; tween(spawnBtn, { rotation: endRot }, { duration: 1200, easing: tween.linear, onFinish: function onFinish() { // Continue loop if still not full and still no enemy if (spawnBtn._rotatingWhileNotFull && (!currentEnemy || !currentEnemy.isAlive)) { _rotateRightLoop(); } } }); }; tween.stop(spawnBtn, { rotation: true }); // Start continuous right rotation (1 full spin per 1.2s) spawnBtn._rotatingWhileNotFull = true; _rotateRightLoop(); } } else if (!hero.healthRefilling && workBtnActive) { setSpawnBtnEnabled(true); // Enable workBtn and restore full opacity workBtn.alpha = 1; workBtn.interactive = true; workBtn.buttonMode = true; // If hero HP is full, remove all effects and restore color tween.stop(hero, { tint: true, alpha: true, scaleX: true, scaleY: true }); hero.tint = 0xffffff; hero.alpha = 1; hero.scaleX = 1; hero.scaleY = 1; // --- Stop spawnBtn rotation and reset to original position, with 45deg right spin if HP just became full and no enemy is alive --- if (spawnBtn._rotatingWhileNotFull) { spawnBtn._rotatingWhileNotFull = false; tween.stop(spawnBtn, { rotation: true }); // If hero HP just became full and no enemy is alive, rotate 45deg right and then reset to 0 if ((!currentEnemy || !currentEnemy.isAlive) && typeof hero.currentHp === "number" && hero.currentHp === getStatsForLevel(heroLevel, "hero").hp) { // Animate 45deg right, then reset to 0 tween(spawnBtn, { rotation: spawnBtn.rotation + Math.PI / 4 }, { duration: 180, easing: tween.cubicOut, onFinish: function onFinish() { tween(spawnBtn, { rotation: 0 }, { duration: 200, easing: tween.cubicOut }); } }); } else { // Animate back to original rotation (0) tween(spawnBtn, { rotation: 0 }, { duration: 200, easing: tween.cubicOut }); } } } // Keep hero slightly lower than vertical center hero.y = 2732 / 2 + 200; // Keep enemy vertically centered and at far right if alive if (currentEnemy && currentEnemy.isAlive) { currentEnemy.x = 2048 - 200; currentEnemy.y = hero.y + 100; // Move enemy a little lower } updateHeroStatsDisplay(); updateEnemyStatsDisplay(); // Keep workBtnCountdownTxt positioned under workBtn if visible if (workBtnCountdownTxt && typeof workBtnCountdownTxt.destroyed === "boolean" && !workBtnCountdownTxt.destroyed && typeof workBtnCountdownTxt.setText === "function" && typeof workBtnCountdownTxt.visible !== "undefined" && workBtnCountdownTxt.visible) { workBtnCountdownTxt.x = workBtn.x; workBtnCountdownTxt.y = workBtn.y + workBtn.height / 2 + 8; } }; // --- Initial UI state --- updateGoldDisplay(); updateUpgradeDisplay(); updateHeroStatsDisplay(); updateEnemyStatsDisplay();
===================================================================
--- original.js
+++ change.js
@@ -488,12 +488,13 @@
closeBtnTxt.anchor.set(0.5, 0.5);
closeBtnTxt.x = closeBtn.x;
closeBtnTxt.y = closeBtn.y;
itemBagWindow.addChild(closeBtnTxt);
- // --- Hide spawnBtn, workBtn, upgradeBtn, and all on-screen texts when X is visible ---
+ // --- Hide spawnBtn, workBtn, upgradeBtn, leftBtn, and all on-screen texts when X is visible ---
spawnBtn.visible = false;
workBtn.visible = false;
upgradeBtn.visible = false;
+ leftBtn.visible = false;
findEnemyTxt.visible = false;
upgradeCostTxt.visible = false;
heroStatsTxt.visible = false;
enemyStatsTxt.visible = false;
@@ -509,8 +510,9 @@
// Restore all UI elements
spawnBtn.visible = true;
workBtn.visible = true;
upgradeBtn.visible = true;
+ leftBtn.visible = true;
findEnemyTxt.visible = true;
upgradeCostTxt.visible = true;
heroStatsTxt.visible = true;
enemyStatsTxt.visible = true;