User prompt
Please fix the bug: 'dynamicAssets[t].push is not a function' in or related to this line: 'var mapBtn = LK.getAsset('map', {' Line Number: 247
User prompt
Please fix the bug: 'dynamicAssets[t].push is not a function' in or related to this line: 'var mapBtn = LK.getAsset('map', {' Line Number: 247
User prompt
Please fix the bug: 'dynamicAssets[t].push is not a function' in or related to this line: 'var mapBtn = LK.getAsset('map', {' Line Number: 244
User prompt
Please fix the bug: 'dynamicAssets[t].push is not a function' in or related to this line: 'var mapBtn = LK.getAsset('map', {' Line Number: 244
User prompt
tamam oyunu çalışır hale getir
User prompt
Please fix the bug: 'dynamicAssets[t].push is not a function' in or related to this line: 'var mapBtn = LK.getAsset('map', {' Line Number: 240
User prompt
Please fix the bug: 'dynamicAssets[t].push is not a function' in or related to this line: 'var mapBtn = LK.getAsset('map', {' Line Number: 240
User prompt
Please fix the bug: 'dynamicAssets[t].push is not a function' in or related to this line: 'var mapBtn = LK.getAsset('map', {' Line Number: 240
User prompt
Please fix the bug: 'dynamicAssets[t].push is not a function' in or related to this line: 'var upgradeBtn = LK.getAsset('upgradeBtn', {' Line Number: 247
User prompt
Please fix the bug: 'dynamicAssets[t].push is not a function' in or related to this line: 'var mapBtn = LK.getAsset('map', {' Line Number: 245
User prompt
Please fix the bug: 'dynamicAssets[t].push is not a function' in or related to this line: 'var mapBtn = LK.getAsset('map', {' Line Number: 240
User prompt
Please fix the bug: 'dynamicAssets[t].push is not a function' in or related to this line: 'var mapBtn = LK.getAsset('map', {' Line Number: 239
User prompt
Please fix the bug: 'Cannot read properties of undefined (reading 'width')' in or related to this line: 'var mapBtn = LK.getAsset('map', {' Line Number: 234
User prompt
Please fix the bug: 'dynamicAssets[t].push is not a function' in or related to this line: 'var mapBtn = LK.getAsset('map', {' Line Number: 349
User prompt
Please fix the bug: 'dynamicAssets[t].push is not a function' in or related to this line: 'var mapBtn = LK.getAsset('map', {' Line Number: 346
User prompt
Please fix the bug: 'dynamicAssets[t].push is not a function' in or related to this line: 'var mapBtn = LK.getAsset('map', {' Line Number: 346
User prompt
Please fix the bug: 'dynamicAssets[t].push is not a function' in or related to this line: 'var mapBtn = LK.getAsset('map', {' Line Number: 348
User prompt
Please fix the bug: 'mapBtn is not defined' in or related to this line: 'mapBtn.x = upgradeBtn.x - upgradeBtn.width / 2 - mapBtn.width / 2 - 30;' Line Number: 350
User prompt
Please fix the bug: 'dynamicAssets[t].push is not a function' in or related to this line: 'var mapBtn = LK.getAsset('map', {' Line Number: 257
User prompt
Please fix the bug: 'dynamicAssets[t].push is not a function' in or related to this line: 'var mapBtn = LK.getAsset('map', {' Line Number: 257
User prompt
Please fix the bug: 'dynamicAssets[t].push is not a function' in or related to this line: 'mapBtn = LK.getAsset('map', {' Line Number: 349
User prompt
Please fix the bug: 'dynamicAssets[t].push is not a function' in or related to this line: 'mapBtn = LK.getAsset('map', {' Line Number: 349
User prompt
Please fix the bug: 'dynamicAssets[t].push is not a function' in or related to this line: 'mapBtn = LK.getAsset('map', {' Line Number: 350
User prompt
Please fix the bug: 'Cannot set properties of undefined (setting 'down')' in or related to this line: 'mapBtn.down = function (x, y, obj) {' Line Number: 298
User prompt
Please fix the bug: 'dynamicAssets[t].push is not a function' in or related to this line: 'var mapBtn = LK.getAsset('map', {' Line Number: 245
/****
* 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
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);
// Work button (to the right of upgradeBtn)
var workBtn = LK.getAsset('workBtn', {
anchorX: 0.5,
anchorY: 0.5
});
// Upgrade button (top center) - create after workBtn so width/height are defined
var upgradeBtn = LK.getAsset('upgradeBtn', {
anchorX: 0.5,
anchorY: 0.5
});
// Map button (to the left of upgradeBtn)
// (Moved after workBtn and upgradeBtn are created to ensure workBtn.width/height are defined)
// 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;
}
};
// --- Map Button State ---
var mapWindow = null;
// (moved mapBtn.down assignment below mapBtn creation)
// --- 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;
// Now that workBtn and upgradeBtn are created, create mapBtn
var mapBtn = LK.getAsset('map', {
anchorX: 0.5,
anchorY: 0.5
});
// Place mapBtn to the left of upgradeBtn, with a small gap
mapBtn.x = upgradeBtn.x - upgradeBtn.width / 2 - mapBtn.width / 2 - 30;
mapBtn.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(mapBtn);
LK.gui.top.addChild(upgradeBtn);
LK.gui.top.addChild(workBtn);
// --- Map Button State ---
mapBtn.down = function (x, y, obj) {
// Animate shrink/grow
tween.stop(mapBtn, {
scaleX: true,
scaleY: true
});
tween(mapBtn, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100,
easing: tween.cubicIn,
onFinish: function onFinish() {
tween(mapBtn, {
scaleX: 1,
scaleY: 1
}, {
duration: 100,
easing: tween.cubicOut,
onFinish: function onFinish() {
// Remove previous mapWindow if exists
if (typeof mapWindow !== "undefined" && mapWindow && mapWindow.parent) {
mapWindow.parent.removeChild(mapWindow);
mapWindow = null;
}
// Create map window container
mapWindow = new Container();
// Parchment-style: use a light brown box, rounded corners, alpha
var winWidth = 1200;
var winHeight = 1400;
var winColor = 0xE6D3A3; // parchment color
var winAlpha = 0.97;
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;
mapWindow.addChild(winBg);
// Add a "Harita" title at the top
var mapTitle = new Text2("Harita", {
size: 90,
fill: 0x7B5B2B
});
mapTitle.anchor.set(0.5, 0);
mapTitle.x = 0;
mapTitle.y = -winHeight / 2 + 60;
mapWindow.addChild(mapTitle);
// Add a close button (X) at top right
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;
mapWindow.addChild(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;
mapWindow.addChild(closeBtnTxt);
// Hide all main UI elements while map is open
spawnBtn.visible = false;
workBtn.visible = false;
upgradeBtn.visible = false;
mapBtn.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;
if (typeof itemBagWindow !== "undefined" && itemBagWindow && itemBagWindow.parent) {
itemBagWindow.parent.removeChild(itemBagWindow);
itemBagWindow = null;
}
// Close logic for X button
closeBtn.down = function () {
if (mapWindow && mapWindow.parent) {
mapWindow.parent.removeChild(mapWindow);
mapWindow = null;
}
// Restore all UI elements
spawnBtn.visible = true;
workBtn.visible = true;
upgradeBtn.visible = true;
mapBtn.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
mapWindow.x = 2048 / 2;
mapWindow.y = 2732 / 2;
// Optionally: add a faint map image in the center
var mapImg = LK.getAsset('map', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 80,
width: winWidth * 0.8,
height: winWidth * 0.8
});
mapImg.alpha = 0.45;
mapWindow.addChild(mapImg);
// Animate mapWindow scale in (parchment pop)
mapWindow.scaleX = 0.7;
mapWindow.scaleY = 0.7;
mapWindow.alpha = 0.2;
game.addChild(mapWindow);
tween(mapWindow, {
scaleX: 1,
scaleY: 1,
alpha: 1
}, {
duration: 220,
easing: tween.cubicOut
});
}
});
}
});
};
// 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, and all on-screen texts when X is visible ---
spawnBtn.visible = false;
workBtn.visible = false;
upgradeBtn.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;
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 (typeof workBtnCountdownTxt !== "undefined" && workBtnCountdownTxt && typeof workBtnCountdownTxt.setText === "function" &&
// Defensive: is a Text2
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
@@ -328,9 +328,12 @@
// Use LK.gui.top (centered horizontally, below top edge)
upgradeBtn.x = LK.gui.top.width / 2;
upgradeBtn.y = 100 + upgradeBtn.height / 2;
// Now that workBtn and upgradeBtn are created, create mapBtn
-// (mapBtn is already created above, do not create again)
+var mapBtn = LK.getAsset('map', {
+ anchorX: 0.5,
+ anchorY: 0.5
+});
// Place mapBtn to the left of upgradeBtn, with a small gap
mapBtn.x = upgradeBtn.x - upgradeBtn.width / 2 - mapBtn.width / 2 - 30;
mapBtn.y = upgradeBtn.y;
// Place workBtn to the right of upgradeBtn, with a small gap