/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var ActionButton = Container.expand(function (actionType) { var self = Container.call(this); self.actionType = actionType; var buttonGraphics = self.attachAsset(actionType, { anchorX: 0.5, anchorY: 0.5 }); // Action image is now visible without text overlay self.down = function (x, y, obj) { // Visual feedback - make button slightly darker when pressed buttonGraphics.tint = 0x666666; if (self.actionType === 'pickaxe') { // Mining action - check for adjacent rocks for (var i = 0; i < rocks.length; i++) { var rock = rocks[i]; if (!rock.destroyed) { var dx = rock.x - player.x; var dy = rock.y - player.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= 80) { rock.hit(); break; // Mine only one rock per click } } } } else if (self.actionType === 'sword') { // Attack action - check for adjacent slimes for (var i = 0; i < slimes.length; i++) { var slime = slimes[i]; if (!slime.destroyed) { var dx = slime.x - player.x; var dy = slime.y - player.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= 80 && hasLineOfSight(player.x, player.y, slime.x, slime.y)) { slime.takeDamage(34); // 3 hits to kill (100/3 = ~34 damage) LK.getSound('attack').play(); break; // Attack only one slime per click } } } } }; self.up = function (x, y, obj) { // Reset button color when released buttonGraphics.tint = 0xFFFFFF; }; return self; }); var DirectionalButton = Container.expand(function (direction) { var self = Container.call(this); self.direction = direction; self.isPressed = false; self.moveTimer = null; var buttonGraphics = self.attachAsset('arrow' + direction.charAt(0).toUpperCase() + direction.slice(1), { anchorX: 0.5, anchorY: 0.5 }); // Method to move player in the button's direction self.movePlayer = function () { var moveDistance = 20; // Increased movement distance for faster speed var newX = player.x; var newY = player.y; if (self.direction === 'Up') { newY = player.y - moveDistance; } else if (self.direction === 'Down') { newY = player.y + moveDistance; } else if (self.direction === 'Left') { newX = player.x - moveDistance; } else if (self.direction === 'Right') { newX = player.x + moveDistance; } // Keep player within bounds newX = Math.max(64, Math.min(1984, newX)); newY = Math.max(164, Math.min(2668, newY)); // Check collision before moving if (!checkCollisionWithSolids(newX, newY, 15)) { player.x = newX; player.y = newY; // Update player facing direction based on movement if (self.direction === 'Left') { player.setFacingDirection('left'); } else if (self.direction === 'Right') { player.setFacingDirection('right'); } else if (self.direction === 'Up') { player.setFacingDirection('up'); } else if (self.direction === 'Down') { player.setFacingDirection('down'); } } }; // Arrow image is now visible without text overlay self.down = function (x, y, obj) { // Visual feedback - make button slightly darker when pressed buttonGraphics.tint = 0x3A7BC8; self.isPressed = true; // Move immediately on press self.movePlayer(); // Start continuous movement timer self.moveTimer = LK.setInterval(function () { if (self.isPressed) { self.movePlayer(); } }, 80); // Move every 80ms while pressed for faster speed }; self.up = function (x, y, obj) { // Reset button color when released buttonGraphics.tint = 0xFFFFFF; self.isPressed = false; // Clear continuous movement timer if (self.moveTimer) { LK.clearInterval(self.moveTimer); self.moveTimer = null; } }; return self; }); var FloorTile = Container.expand(function () { var self = Container.call(this); var tileGraphics = self.attachAsset('floorTile', { anchorX: 0.5, anchorY: 0.5, width: 64, height: 64 }); // Add subtle border to show grid lines tileGraphics.alpha = 0.3; return self; }); var HealthItem = Container.expand(function () { var self = Container.call(this); var heartGraphics = self.attachAsset('heart', { anchorX: 0.5, anchorY: 0.5, width: 32, height: 32 }); self.collected = false; self.healAmount = 25; self.collect = function () { if (self.collected) return; self.collected = true; LK.getSound('collect').play(); player.heal(self.healAmount); // Remove from healthItems array for (var i = healthItems.length - 1; i >= 0; i--) { if (healthItems[i] === self) { healthItems.splice(i, 1); break; } } game.removeChild(self); }; return self; }); var InventoryButton = Container.expand(function () { var self = Container.call(this); var buttonGraphics = self.attachAsset('inventoryButton', { anchorX: 0.5, anchorY: 0.5 }); self.down = function (x, y, obj) { buttonGraphics.tint = 0x666666; // Toggle inventory interface if (inventoryInterface.visible) { inventoryInterface.visible = false; } else { inventoryInterface.visible = true; updateInventoryInterface(); } }; self.up = function (x, y, obj) { buttonGraphics.tint = 0xFFFFFF; }; return self; }); var InventoryInterface = Container.expand(function () { var self = Container.call(this); // Create background panel var background = self.attachAsset('inventoryBackground', { anchorX: 0.5, anchorY: 0.5 }); // Create border var border = self.attachAsset('inventoryBorder', { anchorX: 0.5, anchorY: 0.5 }); self.addChildAt(border, 0); // Title text var titleText = new Text2('Inventory', { size: 40, fill: 0xFFFFFF }); titleText.anchor.set(0.5, 0); titleText.x = 0; titleText.y = -180; self.addChild(titleText); self.itemSlots = []; // Create grid of item slots (6x4 grid) var slotSize = 80; var slotSpacing = 90; var startX = -225; var startY = -120; for (var row = 0; row < 4; row++) { for (var col = 0; col < 6; col++) { var slotContainer = new Container(); // Slot background var slotBg = LK.getAsset('inventorySlot', { anchorX: 0.5, anchorY: 0.5 }); slotContainer.addChild(slotBg); slotContainer.x = startX + col * slotSpacing; slotContainer.y = startY + row * slotSpacing; self.addChild(slotContainer); self.itemSlots.push(slotContainer); } } self.visible = false; return self; }); var Ladder = Container.expand(function () { var self = Container.call(this); var ladderGraphics = self.attachAsset('ladder', { anchorX: 0.5, anchorY: 0.5, width: 64, height: 64 }); self.used = false; self.use = function () { if (self.used) return; self.used = true; currentFloor++; generateFloor(); }; return self; }); var Merchant = Container.expand(function () { var self = Container.call(this); var npcGraphics = self.attachAsset('npc', { anchorX: 0.5, anchorY: 0.5, width: 192, height: 192 }); self.down = function (x, y, obj) { // Open merchant interface if (merchantInterface) { merchantInterface.visible = true; merchantInterface.showPriceGuide(); // Show price guide by default } }; return self; }); var MerchantInterface = Container.expand(function () { var self = Container.call(this); // Create background panel var background = self.attachAsset('inventoryBackground', { anchorX: 0.5, anchorY: 0.5, width: 800, height: 600 }); // Create border var border = self.attachAsset('inventoryBorder', { anchorX: 0.5, anchorY: 0.5, width: 820, height: 620 }); self.addChildAt(border, 0); // Title text var titleText = new Text2('Merchant', { size: 40, fill: 0xFFFFFF }); titleText.anchor.set(0.5, 0); titleText.x = 0; titleText.y = -280; self.addChild(titleText); // Price Guide Button var priceGuideButton = new Container(); var priceGuideBg = priceGuideButton.attachAsset('inventorySlot', { anchorX: 0.5, anchorY: 0.5, width: 200, height: 60 }); var priceGuideText = new Text2('Price Guide', { size: 24, fill: 0xFFFFFF }); priceGuideText.anchor.set(0.5, 0.5); priceGuideButton.addChild(priceGuideText); priceGuideButton.x = -150; priceGuideButton.y = -200; self.addChild(priceGuideButton); // Sell Items Button var sellButton = new Container(); var sellBg = sellButton.attachAsset('inventorySlot', { anchorX: 0.5, anchorY: 0.5, width: 200, height: 60 }); var sellText = new Text2('Sell Items', { size: 24, fill: 0xFFFFFF }); sellText.anchor.set(0.5, 0.5); sellButton.addChild(sellText); sellButton.x = 150; sellButton.y = -200; self.addChild(sellButton); // Content area for price guide or selling interface self.contentArea = new Container(); self.contentArea.y = -100; self.addChild(self.contentArea); // Close button var closeButton = new Container(); var closeBg = closeButton.attachAsset('inventoryButton', { anchorX: 0.5, anchorY: 0.5 }); var closeText = new Text2('X', { size: 30, fill: 0xFF0000 }); closeText.anchor.set(0.5, 0.5); closeButton.addChild(closeText); closeButton.x = 350; closeButton.y = -250; self.addChild(closeButton); // Button event handlers priceGuideButton.down = function (x, y, obj) { priceGuideBg.tint = 0x666666; self.showPriceGuide(); }; priceGuideButton.up = function (x, y, obj) { priceGuideBg.tint = 0xFFFFFF; }; sellButton.down = function (x, y, obj) { sellBg.tint = 0x666666; self.showSellingInterface(); }; sellButton.up = function (x, y, obj) { sellBg.tint = 0xFFFFFF; }; closeButton.down = function (x, y, obj) { closeBg.tint = 0x666666; self.visible = false; }; closeButton.up = function (x, y, obj) { closeBg.tint = 0xFFFFFF; }; // Show price guide self.showPriceGuide = function () { // Clear content area while (self.contentArea.children.length > 0) { self.contentArea.removeChild(self.contentArea.children[0]); } var priceItems = [{ item: 'rock', price: 1 }, { item: 'coal', price: 3 }, { item: 'copper_ore', price: 5 }, { item: 'iron_ore', price: 8 }, { item: 'gold_ore', price: 15 }, { item: 'gem', price: 25 }, { item: 'slime', price: 2 }]; var startY = 0; for (var i = 0; i < priceItems.length; i++) { var itemContainer = new Container(); // Item sprite var itemSprite = LK.getAsset(priceItems[i].item, { anchorX: 0.5, anchorY: 0.5, width: 40, height: 40 }); itemSprite.x = -100; itemContainer.addChild(itemSprite); // Price text var priceText = new Text2(priceItems[i].price + ' coins', { size: 24, fill: 0xFFFFFF }); priceText.anchor.set(0, 0.5); priceText.x = -50; itemContainer.addChild(priceText); itemContainer.y = startY + i * 50; self.contentArea.addChild(itemContainer); } }; // Show selling interface self.showSellingInterface = function () { // Clear content area while (self.contentArea.children.length > 0) { self.contentArea.removeChild(self.contentArea.children[0]); } var yPos = 0; var hasItems = false; for (var item in inventory) { if (inventory[item] > 0) { hasItems = true; var sellItemContainer = new Container(); // Item sprite var itemSprite = LK.getAsset(item, { anchorX: 0.5, anchorY: 0.5, width: 40, height: 40 }); itemSprite.x = -150; sellItemContainer.addChild(itemSprite); // Item info text var itemValue = getItemValue(item); var totalValue = inventory[item] * itemValue; var infoText = new Text2(item + ' x' + inventory[item] + ' = ' + totalValue + ' coins', { size: 20, fill: 0xFFFFFF }); infoText.anchor.set(0, 0.5); infoText.x = -100; sellItemContainer.addChild(infoText); // Sell button for this item var sellItemButton = new Container(); var sellItemBg = sellItemButton.attachAsset('inventorySlot', { anchorX: 0.5, anchorY: 0.5, width: 80, height: 40 }); var sellItemText = new Text2('Sell', { size: 18, fill: 0xFFFFFF }); sellItemText.anchor.set(0.5, 0.5); sellItemButton.addChild(sellItemText); sellItemButton.x = 200; sellItemContainer.addChild(sellItemButton); // Create closure for button handler (function (itemType) { sellItemButton.down = function (x, y, obj) { sellItemBg.tint = 0x666666; // Sell this item type if (inventory[itemType] > 0) { var value = inventory[itemType] * getItemValue(itemType); LK.setScore(LK.getScore() + value); inventory[itemType] = 0; // Flash effect tween(sellItemButton, { alpha: 0.5 }, { duration: 200, onFinish: function onFinish() { tween(sellItemButton, { alpha: 1 }, { duration: 200 }); } }); // Refresh the selling interface LK.setTimeout(function () { self.showSellingInterface(); }, 400); } }; sellItemButton.up = function (x, y, obj) { sellItemBg.tint = 0xFFFFFF; }; })(item); sellItemContainer.y = yPos; self.contentArea.addChild(sellItemContainer); yPos += 60; } } if (!hasItems) { var noItemsText = new Text2('No items to sell!', { size: 24, fill: 0xFFFFFF }); noItemsText.anchor.set(0.5, 0.5); self.contentArea.addChild(noItemsText); } }; self.visible = false; return self; }); var Player = Container.expand(function () { var self = Container.call(this); var playerGraphics = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5, width: 64, height: 64 }); var playerVerticalGraphics = self.attachAsset('playerVertical', { anchorX: 0.5, anchorY: 0.5, width: 64, height: 64 }); playerVerticalGraphics.visible = false; // Hide vertical sprite initially var playerDownGraphics = self.attachAsset('playerDown', { anchorX: 0.5, anchorY: 0.5, width: 64, height: 64 }); playerDownGraphics.visible = false; // Hide down sprite initially self.maxHealth = 100; self.health = self.maxHealth; self.speed = 3; self.attackRange = 80; self.attackDamage = 25; self.lastAttackTime = 0; self.attackCooldown = 500; self.facingDirection = 'right'; // Track which direction player is facing self.lastX = 0; // Track last position to determine movement direction self.lastY = 0; // Method to update sprite direction based on facing self.updateSpriteDirection = function () { if (self.facingDirection === 'left') { playerGraphics.visible = true; playerVerticalGraphics.visible = false; playerDownGraphics.visible = false; playerGraphics.scale.x = -1; // Flip sprite horizontally playerGraphics.rotation = 0; // No rotation } else if (self.facingDirection === 'right') { playerGraphics.visible = true; playerVerticalGraphics.visible = false; playerDownGraphics.visible = false; playerGraphics.scale.x = 1; // Normal sprite orientation playerGraphics.rotation = 0; // No rotation } else if (self.facingDirection === 'up') { playerGraphics.visible = false; playerVerticalGraphics.visible = true; playerDownGraphics.visible = false; playerVerticalGraphics.scale.x = 1; // Normal scale playerVerticalGraphics.rotation = 0; // No rotation - use original up sprite } else if (self.facingDirection === 'down') { playerGraphics.visible = false; playerVerticalGraphics.visible = false; playerDownGraphics.visible = true; playerDownGraphics.scale.x = 1; // Normal scale playerDownGraphics.rotation = 0; // No rotation - use separate down sprite } }; // Method to set facing direction and update sprite self.setFacingDirection = function (direction) { if (direction === 'left' || direction === 'right' || direction === 'up' || direction === 'down') { self.facingDirection = direction; self.updateSpriteDirection(); } }; self.takeDamage = function (damage) { self.health -= damage; if (self.health <= 0) { self.health = 0; LK.showGameOver(); } LK.effects.flashObject(self, 0xFF0000, 300); LK.getSound('hurt').play(); }; self.heal = function (amount) { self.health = Math.min(self.maxHealth, self.health + amount); }; self.canAttack = function () { return LK.ticks - self.lastAttackTime > self.attackCooldown; }; self.canMoveTo = function (x, y) { return !checkCollisionWithSolids(x, y, 15); }; self.update = function () { // Detect movement direction and update facing if (self.x !== self.lastX) { if (self.x > self.lastX) { self.setFacingDirection('right'); } else if (self.x < self.lastX) { self.setFacingDirection('left'); } } else if (self.y !== self.lastY) { if (self.y > self.lastY) { self.setFacingDirection('down'); } else if (self.y < self.lastY) { self.setFacingDirection('up'); } } // Update last position for next frame self.lastX = self.x; self.lastY = self.y; }; self.attack = function () { if (!self.canAttack()) return; self.lastAttackTime = LK.ticks; LK.getSound('attack').play(); // Check for slimes in attack range with line of sight for (var i = 0; i < slimes.length; i++) { var slime = slimes[i]; var dx = slime.x - self.x; var dy = slime.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.attackRange && hasLineOfSight(self.x, self.y, slime.x, slime.y)) { slime.takeDamage(self.attackDamage); } } // Check for rocks in attack range with line of sight for (var i = 0; i < rocks.length; i++) { var rock = rocks[i]; var dx = rock.x - self.x; var dy = rock.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= self.attackRange && hasLineOfSight(self.x, self.y, rock.x, rock.y)) { rock.hit(); } } }; return self; }); var Resource = Container.expand(function (type) { var self = Container.call(this); self.type = type; self.collected = false; var resourceGraphics = self.attachAsset(type, { anchorX: 0.5, anchorY: 0.5, width: 32, height: 32 }); self.collect = function () { if (self.collected) return; self.collected = true; LK.getSound('collect').play(); // Update inventory if (!inventory[self.type]) { inventory[self.type] = 0; } inventory[self.type]++; // Remove from resources array for (var i = resources.length - 1; i >= 0; i--) { if (resources[i] === self) { resources.splice(i, 1); break; } } game.removeChild(self); }; return self; }); var Rock = Container.expand(function (rockType) { var self = Container.call(this); self.rockType = rockType || 'rock'; var rockGraphics = self.attachAsset(self.rockType, { anchorX: 0.5, anchorY: 0.5, width: 64, height: 64 }); self.maxHealth = 3; self.health = self.maxHealth; self.destroyed = false; self.mined = false; self.hit = function () { if (self.destroyed) return; self.health--; LK.getSound('mine_hit').play(); LK.effects.flashObject(self, 0xFFFFFF, 200); if (self.health <= 0) { self.mine(); } }; self.mine = function () { if (self.mined || self.destroyed) return; self.mined = true; // Animate to half size and make collectable tween(rockGraphics, { width: 32, height: 32 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { // Now it becomes a collectable resource self.collectable = true; // If this rock has the ladder, reveal it underneath if (self.hasLadder && !ladder) { ladder = new Ladder(); ladder.x = self.x; ladder.y = self.y; game.addChild(ladder); } } }); }; self.destroy = function () { if (self.destroyed) return; self.destroyed = true; // Drop resources based on rock type var resource; if (self.rockType === 'coal') { resource = new Resource('coal'); } else if (self.rockType === 'copper_ore') { resource = new Resource('copper_ore'); } else if (self.rockType === 'iron_ore') { resource = new Resource('iron_ore'); } else if (self.rockType === 'gold_ore') { resource = new Resource('gold_ore'); } else if (self.rockType === 'gem') { resource = new Resource('gem'); } else { // Regular rock always drops a rock resource resource = new Resource('rock'); } if (resource) { resource.x = self.x; resource.y = self.y; resources.push(resource); game.addChild(resource); } // Ladder is now spawned when mining the pre-determined ladder rock, not randomly on destroy // Remove from rocks array for (var i = rocks.length - 1; i >= 0; i--) { if (rocks[i] === self) { rocks.splice(i, 1); break; } } game.removeChild(self); }; self.collect = function () { if (!self.collectable || self.destroyed) return; LK.getSound('collect').play(); // Update inventory if (!inventory[self.rockType]) { inventory[self.rockType] = 0; } inventory[self.rockType]++; self.destroy(); }; return self; }); var Slime = Container.expand(function () { var self = Container.call(this); var slimeGraphics = self.attachAsset('slime', { anchorX: 0.5, anchorY: 0.5, width: 64, height: 64 }); self.maxHealth = 100; self.health = self.maxHealth; self.speed = 1; self.attackDamage = 15; self.lastAttackTime = 0; self.attackCooldown = 1000; self.attackRange = 50; self.lastDamageTime = 0; self.damageInterval = 100; // 0.1 seconds between damage ticks self.destroyed = false; self.takeDamage = function (damage) { if (self.destroyed) return; self.health -= damage; LK.effects.flashObject(self, 0xFF0000, 200); if (self.health <= 0) { self.destroy(); } }; self.destroy = function () { if (self.destroyed) return; self.destroyed = true; // Always drop slime item var slimeResource = new Resource('slime'); slimeResource.x = self.x; slimeResource.y = self.y; resources.push(slimeResource); game.addChild(slimeResource); // Drop heart sometimes if (Math.random() < 0.3) { var heart = new HealthItem(); heart.x = self.x; heart.y = self.y; healthItems.push(heart); game.addChild(heart); } // Remove from slimes array for (var i = slimes.length - 1; i >= 0; i--) { if (slimes[i] === self) { slimes.splice(i, 1); break; } } // Increase score LK.setScore(LK.getScore() + 10); game.removeChild(self); }; self.update = function () { if (self.destroyed) return; // Check if player is visible (line of sight) var dx = player.x - self.x; var dy = player.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (hasLineOfSight(self.x, self.y, player.x, player.y) && distance < 300) { // Move towards player if visible and within detection range in any direction (including diagonals) var moveX = dx / distance * self.speed; var moveY = dy / distance * self.speed; var newX = self.x + moveX; var newY = self.y + moveY; // Check collision before moving (only with solids and other slimes, not player) if (!checkCollisionWithSolids(newX, newY, 15) && !checkCollisionWithSlimes(newX, newY, 15, self)) { self.x = newX; self.y = newY; } // Apply damage if touching player in any direction (including diagonals) if (distance <= 50 && LK.ticks - self.lastDamageTime > self.damageInterval) { self.lastDamageTime = LK.ticks; player.takeDamage(Math.floor(player.maxHealth * 0.05)); // 5% damage } } }; return self; }); var ToolMerchant = Container.expand(function () { var self = Container.call(this); var npcGraphics = self.attachAsset('toolMerchantNPC', { anchorX: 0.5, anchorY: 0.5, width: 192, height: 192 }); self.down = function (x, y, obj) { // Open tool merchant interface if (toolMerchantInterface) { toolMerchantInterface.visible = true; } }; return self; }); var ToolMerchantInterface = Container.expand(function () { var self = Container.call(this); // Create background panel var background = self.attachAsset('inventoryBackground', { anchorX: 0.5, anchorY: 0.5, width: 800, height: 600 }); // Create border var border = self.attachAsset('inventoryBorder', { anchorX: 0.5, anchorY: 0.5, width: 820, height: 620 }); self.addChildAt(border, 0); // Title text var titleText = new Text2('Tool Shop', { size: 40, fill: 0xFFFFFF }); titleText.anchor.set(0.5, 0); titleText.x = 0; titleText.y = -280; self.addChild(titleText); // Content area for tools self.contentArea = new Container(); self.contentArea.y = -100; self.addChild(self.contentArea); // Close button var closeButton = new Container(); var closeBg = closeButton.attachAsset('inventoryButton', { anchorX: 0.5, anchorY: 0.5 }); var closeText = new Text2('X', { size: 30, fill: 0xFF0000 }); closeText.anchor.set(0.5, 0.5); closeButton.addChild(closeText); closeButton.x = 350; closeButton.y = -250; self.addChild(closeButton); closeButton.down = function (x, y, obj) { closeBg.tint = 0x666666; self.visible = false; }; closeButton.up = function (x, y, obj) { closeBg.tint = 0xFFFFFF; }; // Show available tools self.showTools = function () { // Clear content area while (self.contentArea.children.length > 0) { self.contentArea.removeChild(self.contentArea.children[0]); } var tools = [{ item: 'pickaxe', material: 'Stone', price: 10 }, { item: 'pickaxe', material: 'Copper', price: 25 }, { item: 'pickaxe', material: 'Iron', price: 50 }, { item: 'pickaxe', material: 'Gold', price: 100 }, { item: 'sword', material: 'Stone', price: 15 }, { item: 'sword', material: 'Copper', price: 30 }, { item: 'sword', material: 'Iron', price: 60 }, { item: 'sword', material: 'Gold', price: 120 }]; var yPos = 0; for (var i = 0; i < tools.length; i++) { var toolContainer = new Container(); // Tool sprite var toolSprite = LK.getAsset(tools[i].item, { anchorX: 0.5, anchorY: 0.5, width: 40, height: 40 }); toolSprite.x = -150; // Apply material tint if (tools[i].material === 'Copper') { toolSprite.tint = 0xB87333; } else if (tools[i].material === 'Iron') { toolSprite.tint = 0x778899; } else if (tools[i].material === 'Gold') { toolSprite.tint = 0xFFD700; } else { toolSprite.tint = 0x808080; // Stone } toolContainer.addChild(toolSprite); // Tool info text var infoText = new Text2(tools[i].material + ' ' + tools[i].item + ' - ' + tools[i].price + ' coins', { size: 20, fill: 0xFFFFFF }); infoText.anchor.set(0, 0.5); infoText.x = -100; toolContainer.addChild(infoText); // Buy button var buyButton = new Container(); var buyBg = buyButton.attachAsset('inventorySlot', { anchorX: 0.5, anchorY: 0.5, width: 80, height: 40 }); var buyText = new Text2('Buy', { size: 18, fill: 0xFFFFFF }); buyText.anchor.set(0.5, 0.5); buyButton.addChild(buyText); buyButton.x = 200; toolContainer.addChild(buyButton); // Create closure for button handler (function (tool) { buyButton.down = function (x, y, obj) { buyBg.tint = 0x666666; // Check if player has enough coins var currentCoins = LK.getScore(); if (currentCoins >= tool.price) { // Deduct coins LK.setScore(currentCoins - tool.price); // Add tool to inventory if (!inventory[tool.material.toLowerCase() + '_' + tool.item]) { inventory[tool.material.toLowerCase() + '_' + tool.item] = 0; } inventory[tool.material.toLowerCase() + '_' + tool.item]++; // Flash effect tween(buyButton, { alpha: 0.5 }, { duration: 200, onFinish: function onFinish() { tween(buyButton, { alpha: 1 }, { duration: 200 }); } }); } else { // Not enough coins - flash red tween(buyButton, { tint: 0xFF0000 }, { duration: 200, onFinish: function onFinish() { tween(buyButton, { tint: 0xFFFFFF }, { duration: 200 }); } }); } }; buyButton.up = function (x, y, obj) { buyBg.tint = 0xFFFFFF; }; })(tools[i]); toolContainer.y = yPos; self.contentArea.addChild(toolContainer); yPos += 60; } }; // Initialize with tools display self.showTools(); self.visible = false; return self; }); var Wall = Container.expand(function () { var self = Container.call(this); var wallGraphics = self.attachAsset('wall', { anchorX: 0.5, anchorY: 0.5, width: 64, height: 64 }); return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x2F1B14 }); /**** * Game Code ****/ var player; var rocks = []; var slimes = []; var resources = []; var healthItems = []; var ladder; var inventory = {}; var currentFloor = 0; // Start at floor 0 (surface) var walls = []; var floorTiles = []; var inventoryInterface; var inventoryButton; var merchant; var forestObjects = []; var merchantInterface; var isInMine = false; var locationStatus; var coinDisplay; var toolMerchant; var toolMerchantInterface; function checkCollisionWithWalls(x, y, radius) { for (var i = 0; i < walls.length; i++) { var wall = walls[i]; var dx = Math.abs(x - wall.x); var dy = Math.abs(y - wall.y); if (dx < 32 + radius && dy < 32 + radius) { return true; } } return false; } function checkCollisionWithSolids(x, y, radius) { // Check collision with walls for (var i = 0; i < walls.length; i++) { var wall = walls[i]; var dx = Math.abs(x - wall.x); var dy = Math.abs(y - wall.y); if (dx < 32 + radius && dy < 32 + radius) { return true; } } // Check collision with rocks for (var i = 0; i < rocks.length; i++) { var rock = rocks[i]; if (!rock.destroyed && !rock.mined) { var dx = Math.abs(x - rock.x); var dy = Math.abs(y - rock.y); if (dx < 16 + radius && dy < 16 + radius) { return true; } } } // Check collision with forest objects (trees and bushes) for (var i = 0; i < forestObjects.length; i++) { var forestObj = forestObjects[i]; var dx = Math.abs(x - forestObj.x); var dy = Math.abs(y - forestObj.y); var objRadius = forestObj.width > 64 ? 48 : 24; // Trees are bigger if (dx < objRadius + radius && dy < objRadius + radius) { return true; } } return false; } function checkCollisionWithSlimes(x, y, radius, excludeSlime) { for (var i = 0; i < slimes.length; i++) { var slime = slimes[i]; if (!slime.destroyed && slime !== excludeSlime) { var dx = Math.abs(x - slime.x); var dy = Math.abs(y - slime.y); if (dx < 50 + radius && dy < 50 + radius) { return true; } } } return false; } function checkCollisionWithPlayer(x, y, radius) { if (!player) return false; var dx = Math.abs(x - player.x); var dy = Math.abs(y - player.y); if (dx < 32 + radius && dy < 32 + radius) { return true; } return false; } function hasLineOfSight(x1, y1, x2, y2) { var dx = x2 - x1; var dy = y2 - y1; var distance = Math.sqrt(dx * dx + dy * dy); var steps = Math.floor(distance / 16); for (var i = 0; i <= steps; i++) { var checkX = x1 + dx * i / steps; var checkY = y1 + dy * i / steps; if (checkCollisionWithSolids(checkX, checkY, 8)) { return false; } } return true; } // UI Elements var healthBar; var floorText; var inventoryText; function initializeGame() { player = game.addChild(new Player()); if (currentFloor === 0) { player.x = 1024; player.y = 400; // Start on surface near cave entrance } else { player.x = 1024; player.y = 300; // Start in mine near entrance } // Initialize position tracking player.lastX = player.x; player.lastY = player.y; // Create UI - Health bar as horizontal bar (larger) healthBar = new Container(); var healthBarBg = healthBar.attachAsset('wall', { anchorX: 0, anchorY: 0, width: 400, height: 30 }); healthBarBg.tint = 0x333333; // Dark background var healthBarFill = healthBar.attachAsset('wall', { anchorX: 0, anchorY: 0, width: 396, height: 26 }); healthBarFill.tint = 0xFF0000; // Red health fill healthBarFill.x = 2; healthBarFill.y = 2; healthBar.healthBarFill = healthBarFill; // Store reference for updates LK.gui.topLeft.addChild(healthBar); healthBar.x = 130; healthBar.y = 20; floorText = new Container(); var floorSprite = floorText.attachAsset('ladder', { anchorX: 0, anchorY: 0, width: 40, height: 40 }); floorText.floorSprite = floorSprite; // Store reference for updates var floorNumber = new Text2('1', { size: 40, fill: 0xFFFFFF }); floorNumber.anchor.set(0, 0); floorNumber.x = 50; floorNumber.y = 0; floorText.addChild(floorNumber); floorText.floorNumber = floorNumber; // Store reference for updates var locationText = new Text2('', { size: 30, fill: 0xFFFFFF }); locationText.anchor.set(0, 0); locationText.x = 100; locationText.y = 5; floorText.addChild(locationText); floorText.locationText = locationText; // Store reference for updates LK.gui.top.addChild(floorText); floorText.y = 20; // Create location status indicator next to floor indicator locationStatus = new Container(); var locationSprite = locationStatus.attachAsset('locationTown', { anchorX: 0, anchorY: 0, width: 40, height: 40 }); locationStatus.locationSprite = locationSprite; // Store reference for updates var locationStatusText = new Text2('pueblo', { size: 30, fill: 0xFFFFFF }); locationStatusText.anchor.set(0, 0); locationStatusText.x = 50; locationStatusText.y = 5; locationStatus.addChild(locationStatusText); locationStatus.locationStatusText = locationStatusText; // Store reference for updates LK.gui.top.addChild(locationStatus); locationStatus.x = 200; // Position to the right of floor indicator locationStatus.y = 20; // Create coin display next to location status coinDisplay = new Container(); var coinSprite = coinDisplay.attachAsset('coin', { anchorX: 0, anchorY: 0, width: 40, height: 40 }); var coinText = new Text2('0', { size: 30, fill: 0xFFD700 }); coinText.anchor.set(0, 0); coinText.x = 50; coinText.y = 5; coinDisplay.addChild(coinText); coinDisplay.coinText = coinText; // Store reference for updates LK.gui.top.addChild(coinDisplay); coinDisplay.x = 400; // Position to the right of location status coinDisplay.y = 20; // Create inventory button inventoryButton = new InventoryButton(); inventoryButton.x = -80; inventoryButton.y = 80; LK.gui.topRight.addChild(inventoryButton); // Create inventory interface (initially hidden) inventoryInterface = new InventoryInterface(); inventoryInterface.x = 0; inventoryInterface.y = 0; LK.gui.center.addChild(inventoryInterface); // Create merchant interface (initially hidden) merchantInterface = new MerchantInterface(); merchantInterface.x = 0; merchantInterface.y = 0; LK.gui.center.addChild(merchantInterface); // Create tool merchant interface (initially hidden) toolMerchantInterface = new ToolMerchantInterface(); toolMerchantInterface.x = 0; toolMerchantInterface.y = 0; LK.gui.center.addChild(toolMerchantInterface); generateFloor(); // Create directional control buttons in bottom left var buttonSize = 80; var buttonSpacing = 90; var baseX = 120; var baseY = -200; // Create up arrow button var upButton = new DirectionalButton('Up'); upButton.x = baseX; upButton.y = baseY - buttonSpacing; LK.gui.bottomLeft.addChild(upButton); // Create down arrow button var downButton = new DirectionalButton('Down'); downButton.x = baseX; downButton.y = baseY + buttonSpacing; LK.gui.bottomLeft.addChild(downButton); // Create left arrow button var leftButton = new DirectionalButton('Left'); leftButton.x = baseX - buttonSpacing; leftButton.y = baseY; LK.gui.bottomLeft.addChild(leftButton); // Create right arrow button var rightButton = new DirectionalButton('Right'); rightButton.x = baseX + buttonSpacing; rightButton.y = baseY; LK.gui.bottomLeft.addChild(rightButton); // Create action buttons on the right side var actionBaseX = -120; var actionBaseY = -200; // Create pickaxe button var pickaxeButton = new ActionButton('pickaxe'); pickaxeButton.x = actionBaseX; pickaxeButton.y = actionBaseY - buttonSpacing / 2; LK.gui.bottomRight.addChild(pickaxeButton); // Create sword button var swordButton = new ActionButton('sword'); swordButton.x = actionBaseX; swordButton.y = actionBaseY + buttonSpacing / 2; LK.gui.bottomRight.addChild(swordButton); } function generateFloor() { // Clear existing objects clearFloor(); if (currentFloor === 0) { // Generate surface floor (floor 0) generateSurface(); return; } // Generate floor tiles for grid visualization for (var x = 64; x < 2048; x += 64) { for (var y = 196; y < 2700; y += 64) { var floorTile = new FloorTile(); floorTile.x = x; floorTile.y = y; floorTiles.push(floorTile); game.addChild(floorTile); } } // Generate perimeter walls for (var x = 0; x < 2048; x += 64) { var topWall = new Wall(); topWall.x = x + 32; topWall.y = 132; walls.push(topWall); game.addChild(topWall); var bottomWall = new Wall(); bottomWall.x = x + 32; bottomWall.y = 2700; walls.push(bottomWall); game.addChild(bottomWall); } for (var y = 132; y < 2700; y += 64) { var leftWall = new Wall(); leftWall.x = 32; leftWall.y = y + 32; walls.push(leftWall); game.addChild(leftWall); var rightWall = new Wall(); rightWall.x = 2016; rightWall.y = y + 32; walls.push(rightWall); game.addChild(rightWall); } // Generate structured maze with corridors and chambers generateMazeStructure(); // Pre-determine which rock will contain the ladder var ladderRockIndex = Math.floor(Math.random() * (15 + Math.floor(currentFloor * 2))); var ladderRock = null; // Generate rocks with different types based on floor, placed in accessible areas var numRocks = 15 + Math.floor(currentFloor * 2); for (var i = 0; i < numRocks; i++) { var rockType = 'rock'; // Default rock type var rand = Math.random(); // Higher floors have better chances for rare materials var floorMultiplier = Math.min(currentFloor / 10, 1); // Cap at floor 10 if (rand < 0.3) { rockType = 'coal'; // Common on all floors } else if (rand < 0.3 + 0.2 * floorMultiplier) { rockType = 'copper_ore'; // More common on higher floors } else if (rand < 0.3 + 0.2 * floorMultiplier + 0.15 * floorMultiplier) { rockType = 'iron_ore'; // Rare, more common on higher floors } else if (rand < 0.3 + 0.2 * floorMultiplier + 0.15 * floorMultiplier + 0.1 * floorMultiplier) { rockType = 'gold_ore'; // Very rare, much more common on higher floors } else if (rand < 0.3 + 0.2 * floorMultiplier + 0.15 * floorMultiplier + 0.1 * floorMultiplier + 0.05 * floorMultiplier) { rockType = 'gem'; // Extremely rare, only on higher floors } var rock = new Rock(rockType); var attempts = 0; do { // Generate grid-aligned positions (64x64 grid cells) var gridX = Math.floor(Math.random() * 26) + 3; // Grid positions 3-28 var gridY = Math.floor(Math.random() * 32) + 5; // Grid positions 5-36 rock.x = 64 + gridX * 64; // Center in grid cell rock.y = 196 + gridY * 64; // Center in grid cell attempts++; } while (checkCollisionWithSolids(rock.x, rock.y, 24) && attempts < 100); // If we couldn't find a good spot after 100 attempts, place it along corridors if (attempts >= 100) { var corridorGridX = Math.floor(Math.random() * 18) + 6; // Corridor area grid var corridorGridY = Math.floor(Math.random() * 20) + 9; // Corridor area grid rock.x = 64 + corridorGridX * 64; rock.y = 196 + corridorGridY * 64; // Try a few more times in corridor area var corridorAttempts = 0; while (checkCollisionWithSolids(rock.x, rock.y, 24) && corridorAttempts < 20) { corridorGridX = Math.floor(Math.random() * 18) + 6; corridorGridY = Math.floor(Math.random() * 20) + 9; rock.x = 64 + corridorGridX * 64; rock.y = 196 + corridorGridY * 64; corridorAttempts++; } } // Mark this rock as the ladder rock if it's the chosen one if (i === ladderRockIndex) { rock.hasLadder = true; ladderRock = rock; } rocks.push(rock); game.addChild(rock); } // Generate slimes in accessible areas var numSlimes = 3 + Math.floor(currentFloor * 1.5); for (var i = 0; i < numSlimes; i++) { var slime = new Slime(); var attempts = 0; do { slime.x = 200 + Math.random() * 1648; slime.y = 300 + Math.random() * 2132; attempts++; } while (checkCollisionWithSolids(slime.x, slime.y, 20) && attempts < 100); // If we couldn't find a good spot after 100 attempts, place it along corridors if (attempts >= 100) { slime.x = 400 + Math.random() * 1200; slime.y = 600 + Math.random() * 1400; // Try a few more times in corridor area var corridorAttempts = 0; while (checkCollisionWithSolids(slime.x, slime.y, 20) && corridorAttempts < 20) { slime.x = 400 + Math.random() * 1200; slime.y = 600 + Math.random() * 1400; corridorAttempts++; } } slime.maxHealth += Math.floor(currentFloor * 10); slime.health = slime.maxHealth; slimes.push(slime); game.addChild(slime); } // Create portal at the top center (to return to surface) var portal = LK.getAsset('portalEntrance', { anchorX: 0.5, anchorY: 0.5, width: 192, height: 192 }); portal.x = 1024; // Center horizontally portal.y = 300; // Consistent position with surface portal.isPortal = true; game.addChild(portal); // Ladder will be generated when mining rocks ladder = null; // Update floor text and sprite based on location if (currentFloor === 0) { // On surface - use tree sprite and show "Pueblo Pochis" floorText.removeChild(floorText.floorSprite); floorText.floorSprite = floorText.attachAsset('tree', { anchorX: 0, anchorY: 0, width: 40, height: 40 }); floorText.addChildAt(floorText.floorSprite, 0); floorText.floorNumber.setText('0'); floorText.locationText.setText('Pueblo Pochis'); // Update location status indicator locationStatus.removeChild(locationStatus.locationSprite); locationStatus.locationSprite = locationStatus.attachAsset('locationTown', { anchorX: 0, anchorY: 0, width: 40, height: 40 }); locationStatus.addChildAt(locationStatus.locationSprite, 0); locationStatus.locationStatusText.setText('pueblo'); } else { // In mine - use ladder sprite and show floor number floorText.removeChild(floorText.floorSprite); floorText.floorSprite = floorText.attachAsset('ladder', { anchorX: 0, anchorY: 0, width: 40, height: 40 }); floorText.addChildAt(floorText.floorSprite, 0); floorText.floorNumber.setText(currentFloor.toString()); floorText.locationText.setText(''); // Update location status indicator locationStatus.removeChild(locationStatus.locationSprite); locationStatus.locationSprite = locationStatus.attachAsset('locationMine', { anchorX: 0, anchorY: 0, width: 40, height: 40 }); locationStatus.addChildAt(locationStatus.locationSprite, 0); locationStatus.locationStatusText.setText('minas'); } } function clearFloor() { // Remove all floor tiles for (var i = 0; i < floorTiles.length; i++) { game.removeChild(floorTiles[i]); } floorTiles = []; // Remove all walls for (var i = 0; i < walls.length; i++) { game.removeChild(walls[i]); } walls = []; // Remove all rocks for (var i = 0; i < rocks.length; i++) { game.removeChild(rocks[i]); } rocks = []; // Remove all slimes for (var i = 0; i < slimes.length; i++) { game.removeChild(slimes[i]); } slimes = []; // Remove all resources for (var i = 0; i < resources.length; i++) { game.removeChild(resources[i]); } resources = []; // Remove all health items for (var i = 0; i < healthItems.length; i++) { game.removeChild(healthItems[i]); } healthItems = []; // Remove ladder if (ladder) { game.removeChild(ladder); ladder = null; } // Remove forest objects for (var i = 0; i < forestObjects.length; i++) { game.removeChild(forestObjects[i]); } forestObjects = []; // Remove merchant if (merchant) { game.removeChild(merchant); merchant = null; } // Remove tool merchant if (toolMerchant) { game.removeChild(toolMerchant); toolMerchant = null; } } function updateInventoryInterface() { // Clear existing items from slots for (var i = 0; i < inventoryInterface.itemSlots.length; i++) { var slot = inventoryInterface.itemSlots[i]; // Remove all children except the background (first child) while (slot.children.length > 1) { slot.removeChild(slot.children[slot.children.length - 1]); } } // Add items to slots var slotIndex = 0; for (var item in inventory) { if (inventory[item] > 0 && slotIndex < inventoryInterface.itemSlots.length) { var slot = inventoryInterface.itemSlots[slotIndex]; // Add item sprite var itemSprite = LK.getAsset(item, { anchorX: 0.5, anchorY: 0.5, width: 50, height: 50 }); itemSprite.x = 0; itemSprite.y = -10; slot.addChild(itemSprite); // Add quantity text var quantityText = new Text2(inventory[item].toString(), { size: 20, fill: 0xFFFFFF }); quantityText.anchor.set(0.5, 0); quantityText.x = 0; quantityText.y = 20; slot.addChild(quantityText); slotIndex++; } } } function updateUI() { // Update health bar - scale the fill based on health percentage (horizontal) var healthPercent = player.health / player.maxHealth; healthBar.healthBarFill.width = 396 * healthPercent; // Change health bar color based on percentage if (healthPercent > 0.66) { tween(healthBar.healthBarFill, { tint: 0x00FF00 }, { duration: 200 }); // Green for healthy } else if (healthPercent > 0.33) { tween(healthBar.healthBarFill, { tint: 0xFFFF00 }, { duration: 200 }); // Yellow for medium health } else { tween(healthBar.healthBarFill, { tint: 0xFF0000 }, { duration: 200 }); // Red for low health } // Update coin display if (coinDisplay && coinDisplay.coinText) { coinDisplay.coinText.setText(LK.getScore().toString()); } // Inventory is now handled by the inventory interface when opened } var dragNode = null; function handleMove(x, y, obj) { if (dragNode) { var newX = x; var newY = y; // Keep player within bounds newX = Math.max(64, Math.min(1984, newX)); newY = Math.max(164, Math.min(2668, newY)); // Check collision with walls and rocks if (!checkCollisionWithSolids(newX, newY, 15)) { var oldX = dragNode.x; dragNode.x = newX; dragNode.y = newY; // Update player facing direction based on drag movement if (dragNode === player) { var oldY = dragNode.y; if (newX !== oldX) { if (newX > oldX) { player.setFacingDirection('right'); } else if (newX < oldX) { player.setFacingDirection('left'); } } else if (newY !== oldY) { if (newY > oldY) { player.setFacingDirection('down'); } else if (newY < oldY) { player.setFacingDirection('up'); } } } } } } game.move = handleMove; game.down = function (x, y, obj) { dragNode = player; handleMove(x, y, obj); }; game.up = function (x, y, obj) { dragNode = null; }; game.update = function () { if (!player) return; // Update player player.update(); // Update slimes for (var i = 0; i < slimes.length; i++) { slimes[i].update(); } // Slimes now handle their own damage timing individually // Automatic mining removed - now controlled by left click // Check resource collection for (var i = resources.length - 1; i >= 0; i--) { var resource = resources[i]; var dx = resource.x - player.x; var dy = resource.y - player.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 40) { resource.collect(); } } // Check mined rock collection for (var i = rocks.length - 1; i >= 0; i--) { var rock = rocks[i]; if (rock.collectable && !rock.destroyed) { var dx = rock.x - player.x; var dy = rock.y - player.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 40) { rock.collect(); } } } // Check health item collection for (var i = healthItems.length - 1; i >= 0; i--) { var healthItem = healthItems[i]; var dx = healthItem.x - player.x; var dy = healthItem.y - player.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 40) { healthItem.collect(); } } // Check ladder interaction (only in mine floors) if (ladder && !ladder.used && currentFloor > 0) { var dx = ladder.x - player.x; var dy = ladder.y - player.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 50) { ladder.use(); } } // Check portal interactions var allChildren = game.children; for (var i = 0; i < allChildren.length; i++) { var child = allChildren[i]; if (child.isPortal) { var dx = child.x - player.x; var dy = child.y - player.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 100) { if (currentFloor === 0) { // Enter mine (go to floor 1) currentFloor = 1; isInMine = true; generateFloor(); // Spawn player 4 blocks (256 pixels) below the portal player.x = 1024; player.y = 300 + 256; } else { // Exit mine (go to pueblo pochis - floor 0) currentFloor = 0; isInMine = false; generateFloor(); // Spawn player 4 blocks (256 pixels) below the portal player.x = 1024; player.y = 300 + 256; } break; } } } // Update UI updateUI(); }; // Initialize the game initializeGame(); function generateMazeStructure() { // Create grid for maze generation (30x38 cells, each cell is 64x64 pixels) var gridWidth = 30; var gridHeight = 38; var cellSize = 64; var startX = 96; var startY = 196; // Create a grid to track where corridors are var corridorGrid = []; for (var x = 0; x < gridWidth; x++) { corridorGrid[x] = []; for (var y = 0; y < gridHeight; y++) { corridorGrid[x][y] = false; } } // Create main entrance tunnel from top-center var entranceX = Math.floor(gridWidth / 2); for (var y = 2; y < 8; y++) { corridorGrid[entranceX][y] = true; // Make entrance wider (3 tiles wide) if (entranceX - 1 >= 0) corridorGrid[entranceX - 1][y] = true; if (entranceX + 1 < gridWidth) corridorGrid[entranceX + 1][y] = true; } // Create main horizontal distribution corridor var mainCorridorY = 8; for (var x = 4; x < gridWidth - 4; x++) { corridorGrid[x][mainCorridorY] = true; // Make main corridor wider corridorGrid[x][mainCorridorY + 1] = true; } // Create realistic mining tunnels branching from main corridor var numMainTunnels = 4 + Math.floor(currentFloor / 3); var tunnelSpacing = Math.floor((gridWidth - 8) / numMainTunnels); for (var i = 0; i < numMainTunnels; i++) { var tunnelX = 4 + i * tunnelSpacing + Math.floor(Math.random() * (tunnelSpacing / 2)); var tunnelLength = 8 + Math.floor(Math.random() * 12); var tunnelStartY = mainCorridorY + 2; // Create main mining tunnel going down for (var y = tunnelStartY; y < Math.min(tunnelStartY + tunnelLength, gridHeight - 2); y++) { corridorGrid[tunnelX][y] = true; // Add slight width variation to make it more natural if (Math.random() > 0.6) { if (tunnelX - 1 >= 2) corridorGrid[tunnelX - 1][y] = true; } else if (Math.random() > 0.6) { if (tunnelX + 1 < gridWidth - 2) corridorGrid[tunnelX + 1][y] = true; } } // Create mining chambers at the end of tunnels if (tunnelStartY + tunnelLength < gridHeight - 4) { var chamberY = tunnelStartY + tunnelLength - 2; var chamberSize = 2 + Math.floor(Math.random() * 2); // 2x2 or 3x3 chamber for (var cx = -chamberSize; cx <= chamberSize; cx++) { for (var cy = -1; cy <= chamberSize; cy++) { var newX = tunnelX + cx; var newY = chamberY + cy; if (newX >= 2 && newX < gridWidth - 2 && newY >= 2 && newY < gridHeight - 2) { corridorGrid[newX][newY] = true; } } } } // Create side branches from main tunnels (like real mine shafts) var numSideBranches = 1 + Math.floor(Math.random() * 2); for (var j = 0; j < numSideBranches; j++) { var branchY = tunnelStartY + 3 + Math.floor(Math.random() * (tunnelLength - 6)); var branchDirection = Math.random() > 0.5 ? 1 : -1; var branchLength = 3 + Math.floor(Math.random() * 5); for (var k = 1; k <= branchLength; k++) { var branchX = tunnelX + k * branchDirection; if (branchX >= 2 && branchX < gridWidth - 2) { corridorGrid[branchX][branchY] = true; // Small chamber at end of side branch if (k === branchLength) { if (branchY - 1 >= 2) corridorGrid[branchX][branchY - 1] = true; if (branchY + 1 < gridHeight - 2) corridorGrid[branchX][branchY + 1] = true; } } } } } // Create connecting tunnels between some main tunnels (crosscuts) var numConnections = Math.floor(numMainTunnels / 2); for (var i = 0; i < numConnections; i++) { var connectionY = mainCorridorY + 5 + Math.floor(Math.random() * 10); var startX = 4 + Math.floor(Math.random() * (gridWidth - 12)); var endX = startX + 4 + Math.floor(Math.random() * 6); for (var x = startX; x <= Math.min(endX, gridWidth - 3); x++) { if (connectionY >= 2 && connectionY < gridHeight - 2) { corridorGrid[x][connectionY] = true; } } } // Convert corridor grid to walls (fill in non-corridor spaces) for (var x = 2; x < gridWidth - 2; x++) { for (var y = 2; y < gridHeight - 2; y++) { if (!corridorGrid[x][y]) { var wall = new Wall(); // Align wall to grid cell center (64x64 grid cells) wall.x = 64 + x * cellSize; // Center in grid cell wall.y = 196 + y * cellSize; // Center in grid cell walls.push(wall); game.addChild(wall); } } } // Add structural support pillars in wider areas var numPillars = Math.floor(currentFloor / 3); for (var i = 0; i < numPillars; i++) { var pillarX = Math.floor(6 + Math.random() * (gridWidth - 12)); var pillarY = Math.floor(mainCorridorY + 3 + Math.random() * (gridHeight - mainCorridorY - 6)); // Only place pillar if it's in a corridor and won't block paths if (corridorGrid[pillarX][pillarY]) { var canPlace = true; // Check if placing pillar would block critical paths for (var dx = -1; dx <= 1 && canPlace; dx++) { for (var dy = -1; dy <= 1 && canPlace; dy++) { var checkX = pillarX + dx; var checkY = pillarY + dy; if (checkX >= 0 && checkX < gridWidth && checkY >= 0 && checkY < gridHeight) { // Don't place if it would create a dead end if (!corridorGrid[checkX][checkY] && (dx === 0 || dy === 0)) { var adjacentCorridors = 0; if (checkX > 0 && corridorGrid[checkX - 1][checkY]) adjacentCorridors++; if (checkX < gridWidth - 1 && corridorGrid[checkX + 1][checkY]) adjacentCorridors++; if (checkY > 0 && corridorGrid[checkX][checkY - 1]) adjacentCorridors++; if (checkY < gridHeight - 1 && corridorGrid[checkX][checkY + 1]) adjacentCorridors++; if (adjacentCorridors < 2) canPlace = false; } } } } if (canPlace && Math.random() > 0.3) { var wall = new Wall(); // Align pillar wall to grid cell center (64x64 grid cells) wall.x = 64 + pillarX * cellSize; // Center in grid cell wall.y = 196 + pillarY * cellSize; // Center in grid cell walls.push(wall); game.addChild(wall); } } } } function generateSurface() { // Generate grass floor tiles for (var x = 64; x < 2048; x += 64) { for (var y = 196; y < 2700; y += 64) { var grassTile = LK.getAsset('grass', { anchorX: 0.5, anchorY: 0.5, width: 64, height: 64 }); grassTile.x = x; grassTile.y = y; grassTile.alpha = 0.7; floorTiles.push(grassTile); game.addChild(grassTile); } } // Ensure player renders above grass tiles by moving to front if (player) { game.removeChild(player); game.addChild(player); } // Create consistent town layout // Mine entrance (portal) at the north var portal = LK.getAsset('portalEntrance', { anchorX: 0.5, anchorY: 0.5, width: 192, height: 192 }); portal.x = 1024; // Center horizontally portal.y = 300; // North position portal.isPortal = true; game.addChild(portal); // Create main path from mine to town center (vertical stone path) var pathTilePositions = [{ x: 1024, y: 500 }, { x: 1024, y: 564 }, { x: 1024, y: 628 }, { x: 1024, y: 692 }, { x: 1024, y: 756 }, { x: 1024, y: 820 }, { x: 1024, y: 884 }, { x: 1024, y: 948 }, { x: 1024, y: 1012 }, { x: 1024, y: 1076 }, { x: 1024, y: 1140 }, { x: 1024, y: 1204 }, { x: 1024, y: 1268 }, { x: 1024, y: 1332 }, { x: 1024, y: 1396 }, { x: 1024, y: 1460 }]; // Add path tiles for (var i = 0; i < pathTilePositions.length; i++) { var pathTile = LK.getAsset('floorTile', { anchorX: 0.5, anchorY: 0.5, width: 64, height: 64 }); pathTile.x = pathTilePositions[i].x; pathTile.y = pathTilePositions[i].y; pathTile.alpha = 0.8; floorTiles.push(pathTile); game.addChild(pathTile); } // Create houses along the path (consistent positions) var housePositions = [{ x: 768, y: 700 }, // Left side house 1 { x: 1280, y: 700 }, // Right side house 1 { x: 768, y: 900 }, // Left side house 2 { x: 1280, y: 900 }, // Right side house 2 { x: 768, y: 1100 }, // Left side house 3 { x: 1280, y: 1100 }, // Right side house 3 { x: 768, y: 1300 }, // Left side house 4 { x: 1280, y: 1300 } // Right side house 4 ]; // Create houses using wall assets as house blocks for (var i = 0; i < housePositions.length; i++) { // Main house structure (3x3 blocks) for (var hx = -1; hx <= 1; hx++) { for (var hy = -1; hy <= 1; hy++) { var houseBlock = LK.getAsset('wall', { anchorX: 0.5, anchorY: 0.5, width: 64, height: 64 }); houseBlock.x = housePositions[i].x + hx * 64; houseBlock.y = housePositions[i].y + hy * 64; houseBlock.tint = 0x8B4513; // Brown color for houses forestObjects.push(houseBlock); game.addChild(houseBlock); } } } // Position NPCs near houses consistently merchant = new Merchant(); merchant.x = 700; // Near left side houses merchant.y = 800; game.addChild(merchant); toolMerchant = new ToolMerchant(); toolMerchant.x = 1350; // Near right side houses toolMerchant.y = 800; game.addChild(toolMerchant); // Place trees in organized clusters around the town perimeter var treeClusterPositions = [ // Left forest cluster { x: 300, y: 500 }, { x: 364, y: 500 }, { x: 428, y: 500 }, { x: 300, y: 600 }, { x: 364, y: 600 }, { x: 428, y: 600 }, { x: 300, y: 700 }, { x: 364, y: 700 }, { x: 428, y: 700 }, // Right forest cluster { x: 1620, y: 500 }, { x: 1684, y: 500 }, { x: 1748, y: 500 }, { x: 1620, y: 600 }, { x: 1684, y: 600 }, { x: 1748, y: 600 }, { x: 1620, y: 700 }, { x: 1684, y: 700 }, { x: 1748, y: 700 }, // Bottom forest clusters { x: 500, y: 1600 }, { x: 564, y: 1600 }, { x: 628, y: 1600 }, { x: 1420, y: 1600 }, { x: 1484, y: 1600 }, { x: 1548, y: 1600 }, // Corner clusters { x: 200, y: 300 }, { x: 264, y: 300 }, { x: 200, y: 364 }, { x: 1784, y: 300 }, { x: 1848, y: 300 }, { x: 1784, y: 364 }]; for (var i = 0; i < treeClusterPositions.length; i++) { var tree = LK.getAsset('tree', { anchorX: 0.5, anchorY: 0.5, width: 128, height: 128 }); tree.x = treeClusterPositions[i].x; tree.y = treeClusterPositions[i].y; forestObjects.push(tree); game.addChild(tree); } // Place bushes in organized pattern between trees and houses var bushPositions = [ // Around left houses { x: 600, y: 650 }, { x: 600, y: 750 }, { x: 600, y: 850 }, { x: 600, y: 950 }, { x: 500, y: 800 }, { x: 500, y: 1000 }, { x: 500, y: 1200 }, // Around right houses { x: 1450, y: 650 }, { x: 1450, y: 750 }, { x: 1450, y: 850 }, { x: 1450, y: 950 }, { x: 1550, y: 800 }, { x: 1550, y: 1000 }, { x: 1550, y: 1200 }, // Along path edges { x: 900, y: 600 }, { x: 1150, y: 600 }, { x: 900, y: 1000 }, { x: 1150, y: 1000 }, { x: 900, y: 1400 }, { x: 1150, y: 1400 }, // Scattered decorative bushes { x: 400, y: 900 }, { x: 1650, y: 900 }, { x: 400, y: 1300 }, { x: 1650, y: 1300 }]; for (var i = 0; i < bushPositions.length; i++) { var bush = LK.getAsset('bush', { anchorX: 0.5, anchorY: 0.5, width: 64, height: 64 }); bush.x = bushPositions[i].x; bush.y = bushPositions[i].y; forestObjects.push(bush); game.addChild(bush); } isInMine = false; } function openMerchantInterface() { // Simple merchant interaction - sell all items var totalValue = 0; var itemsSold = []; for (var item in inventory) { if (inventory[item] > 0) { var itemValue = getItemValue(item); var itemTotal = inventory[item] * itemValue; totalValue += itemTotal; itemsSold.push(item + ' x' + inventory[item] + ' = ' + itemTotal + ' coins'); inventory[item] = 0; // Clear inventory } } if (totalValue > 0) { LK.setScore(LK.getScore() + totalValue); // Visual feedback LK.effects.flashScreen(0x00FF00, 500); } } function getItemValue(itemType) { switch (itemType) { case 'rock': return 1; case 'coal': return 3; case 'copper_ore': return 5; case 'iron_ore': return 8; case 'gold_ore': return 15; case 'gem': return 25; case 'slime': return 2; default: return 1; } }
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var ActionButton = Container.expand(function (actionType) {
var self = Container.call(this);
self.actionType = actionType;
var buttonGraphics = self.attachAsset(actionType, {
anchorX: 0.5,
anchorY: 0.5
});
// Action image is now visible without text overlay
self.down = function (x, y, obj) {
// Visual feedback - make button slightly darker when pressed
buttonGraphics.tint = 0x666666;
if (self.actionType === 'pickaxe') {
// Mining action - check for adjacent rocks
for (var i = 0; i < rocks.length; i++) {
var rock = rocks[i];
if (!rock.destroyed) {
var dx = rock.x - player.x;
var dy = rock.y - player.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= 80) {
rock.hit();
break; // Mine only one rock per click
}
}
}
} else if (self.actionType === 'sword') {
// Attack action - check for adjacent slimes
for (var i = 0; i < slimes.length; i++) {
var slime = slimes[i];
if (!slime.destroyed) {
var dx = slime.x - player.x;
var dy = slime.y - player.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= 80 && hasLineOfSight(player.x, player.y, slime.x, slime.y)) {
slime.takeDamage(34); // 3 hits to kill (100/3 = ~34 damage)
LK.getSound('attack').play();
break; // Attack only one slime per click
}
}
}
}
};
self.up = function (x, y, obj) {
// Reset button color when released
buttonGraphics.tint = 0xFFFFFF;
};
return self;
});
var DirectionalButton = Container.expand(function (direction) {
var self = Container.call(this);
self.direction = direction;
self.isPressed = false;
self.moveTimer = null;
var buttonGraphics = self.attachAsset('arrow' + direction.charAt(0).toUpperCase() + direction.slice(1), {
anchorX: 0.5,
anchorY: 0.5
});
// Method to move player in the button's direction
self.movePlayer = function () {
var moveDistance = 20; // Increased movement distance for faster speed
var newX = player.x;
var newY = player.y;
if (self.direction === 'Up') {
newY = player.y - moveDistance;
} else if (self.direction === 'Down') {
newY = player.y + moveDistance;
} else if (self.direction === 'Left') {
newX = player.x - moveDistance;
} else if (self.direction === 'Right') {
newX = player.x + moveDistance;
}
// Keep player within bounds
newX = Math.max(64, Math.min(1984, newX));
newY = Math.max(164, Math.min(2668, newY));
// Check collision before moving
if (!checkCollisionWithSolids(newX, newY, 15)) {
player.x = newX;
player.y = newY;
// Update player facing direction based on movement
if (self.direction === 'Left') {
player.setFacingDirection('left');
} else if (self.direction === 'Right') {
player.setFacingDirection('right');
} else if (self.direction === 'Up') {
player.setFacingDirection('up');
} else if (self.direction === 'Down') {
player.setFacingDirection('down');
}
}
};
// Arrow image is now visible without text overlay
self.down = function (x, y, obj) {
// Visual feedback - make button slightly darker when pressed
buttonGraphics.tint = 0x3A7BC8;
self.isPressed = true;
// Move immediately on press
self.movePlayer();
// Start continuous movement timer
self.moveTimer = LK.setInterval(function () {
if (self.isPressed) {
self.movePlayer();
}
}, 80); // Move every 80ms while pressed for faster speed
};
self.up = function (x, y, obj) {
// Reset button color when released
buttonGraphics.tint = 0xFFFFFF;
self.isPressed = false;
// Clear continuous movement timer
if (self.moveTimer) {
LK.clearInterval(self.moveTimer);
self.moveTimer = null;
}
};
return self;
});
var FloorTile = Container.expand(function () {
var self = Container.call(this);
var tileGraphics = self.attachAsset('floorTile', {
anchorX: 0.5,
anchorY: 0.5,
width: 64,
height: 64
});
// Add subtle border to show grid lines
tileGraphics.alpha = 0.3;
return self;
});
var HealthItem = Container.expand(function () {
var self = Container.call(this);
var heartGraphics = self.attachAsset('heart', {
anchorX: 0.5,
anchorY: 0.5,
width: 32,
height: 32
});
self.collected = false;
self.healAmount = 25;
self.collect = function () {
if (self.collected) return;
self.collected = true;
LK.getSound('collect').play();
player.heal(self.healAmount);
// Remove from healthItems array
for (var i = healthItems.length - 1; i >= 0; i--) {
if (healthItems[i] === self) {
healthItems.splice(i, 1);
break;
}
}
game.removeChild(self);
};
return self;
});
var InventoryButton = Container.expand(function () {
var self = Container.call(this);
var buttonGraphics = self.attachAsset('inventoryButton', {
anchorX: 0.5,
anchorY: 0.5
});
self.down = function (x, y, obj) {
buttonGraphics.tint = 0x666666;
// Toggle inventory interface
if (inventoryInterface.visible) {
inventoryInterface.visible = false;
} else {
inventoryInterface.visible = true;
updateInventoryInterface();
}
};
self.up = function (x, y, obj) {
buttonGraphics.tint = 0xFFFFFF;
};
return self;
});
var InventoryInterface = Container.expand(function () {
var self = Container.call(this);
// Create background panel
var background = self.attachAsset('inventoryBackground', {
anchorX: 0.5,
anchorY: 0.5
});
// Create border
var border = self.attachAsset('inventoryBorder', {
anchorX: 0.5,
anchorY: 0.5
});
self.addChildAt(border, 0);
// Title text
var titleText = new Text2('Inventory', {
size: 40,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0);
titleText.x = 0;
titleText.y = -180;
self.addChild(titleText);
self.itemSlots = [];
// Create grid of item slots (6x4 grid)
var slotSize = 80;
var slotSpacing = 90;
var startX = -225;
var startY = -120;
for (var row = 0; row < 4; row++) {
for (var col = 0; col < 6; col++) {
var slotContainer = new Container();
// Slot background
var slotBg = LK.getAsset('inventorySlot', {
anchorX: 0.5,
anchorY: 0.5
});
slotContainer.addChild(slotBg);
slotContainer.x = startX + col * slotSpacing;
slotContainer.y = startY + row * slotSpacing;
self.addChild(slotContainer);
self.itemSlots.push(slotContainer);
}
}
self.visible = false;
return self;
});
var Ladder = Container.expand(function () {
var self = Container.call(this);
var ladderGraphics = self.attachAsset('ladder', {
anchorX: 0.5,
anchorY: 0.5,
width: 64,
height: 64
});
self.used = false;
self.use = function () {
if (self.used) return;
self.used = true;
currentFloor++;
generateFloor();
};
return self;
});
var Merchant = Container.expand(function () {
var self = Container.call(this);
var npcGraphics = self.attachAsset('npc', {
anchorX: 0.5,
anchorY: 0.5,
width: 192,
height: 192
});
self.down = function (x, y, obj) {
// Open merchant interface
if (merchantInterface) {
merchantInterface.visible = true;
merchantInterface.showPriceGuide(); // Show price guide by default
}
};
return self;
});
var MerchantInterface = Container.expand(function () {
var self = Container.call(this);
// Create background panel
var background = self.attachAsset('inventoryBackground', {
anchorX: 0.5,
anchorY: 0.5,
width: 800,
height: 600
});
// Create border
var border = self.attachAsset('inventoryBorder', {
anchorX: 0.5,
anchorY: 0.5,
width: 820,
height: 620
});
self.addChildAt(border, 0);
// Title text
var titleText = new Text2('Merchant', {
size: 40,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0);
titleText.x = 0;
titleText.y = -280;
self.addChild(titleText);
// Price Guide Button
var priceGuideButton = new Container();
var priceGuideBg = priceGuideButton.attachAsset('inventorySlot', {
anchorX: 0.5,
anchorY: 0.5,
width: 200,
height: 60
});
var priceGuideText = new Text2('Price Guide', {
size: 24,
fill: 0xFFFFFF
});
priceGuideText.anchor.set(0.5, 0.5);
priceGuideButton.addChild(priceGuideText);
priceGuideButton.x = -150;
priceGuideButton.y = -200;
self.addChild(priceGuideButton);
// Sell Items Button
var sellButton = new Container();
var sellBg = sellButton.attachAsset('inventorySlot', {
anchorX: 0.5,
anchorY: 0.5,
width: 200,
height: 60
});
var sellText = new Text2('Sell Items', {
size: 24,
fill: 0xFFFFFF
});
sellText.anchor.set(0.5, 0.5);
sellButton.addChild(sellText);
sellButton.x = 150;
sellButton.y = -200;
self.addChild(sellButton);
// Content area for price guide or selling interface
self.contentArea = new Container();
self.contentArea.y = -100;
self.addChild(self.contentArea);
// Close button
var closeButton = new Container();
var closeBg = closeButton.attachAsset('inventoryButton', {
anchorX: 0.5,
anchorY: 0.5
});
var closeText = new Text2('X', {
size: 30,
fill: 0xFF0000
});
closeText.anchor.set(0.5, 0.5);
closeButton.addChild(closeText);
closeButton.x = 350;
closeButton.y = -250;
self.addChild(closeButton);
// Button event handlers
priceGuideButton.down = function (x, y, obj) {
priceGuideBg.tint = 0x666666;
self.showPriceGuide();
};
priceGuideButton.up = function (x, y, obj) {
priceGuideBg.tint = 0xFFFFFF;
};
sellButton.down = function (x, y, obj) {
sellBg.tint = 0x666666;
self.showSellingInterface();
};
sellButton.up = function (x, y, obj) {
sellBg.tint = 0xFFFFFF;
};
closeButton.down = function (x, y, obj) {
closeBg.tint = 0x666666;
self.visible = false;
};
closeButton.up = function (x, y, obj) {
closeBg.tint = 0xFFFFFF;
};
// Show price guide
self.showPriceGuide = function () {
// Clear content area
while (self.contentArea.children.length > 0) {
self.contentArea.removeChild(self.contentArea.children[0]);
}
var priceItems = [{
item: 'rock',
price: 1
}, {
item: 'coal',
price: 3
}, {
item: 'copper_ore',
price: 5
}, {
item: 'iron_ore',
price: 8
}, {
item: 'gold_ore',
price: 15
}, {
item: 'gem',
price: 25
}, {
item: 'slime',
price: 2
}];
var startY = 0;
for (var i = 0; i < priceItems.length; i++) {
var itemContainer = new Container();
// Item sprite
var itemSprite = LK.getAsset(priceItems[i].item, {
anchorX: 0.5,
anchorY: 0.5,
width: 40,
height: 40
});
itemSprite.x = -100;
itemContainer.addChild(itemSprite);
// Price text
var priceText = new Text2(priceItems[i].price + ' coins', {
size: 24,
fill: 0xFFFFFF
});
priceText.anchor.set(0, 0.5);
priceText.x = -50;
itemContainer.addChild(priceText);
itemContainer.y = startY + i * 50;
self.contentArea.addChild(itemContainer);
}
};
// Show selling interface
self.showSellingInterface = function () {
// Clear content area
while (self.contentArea.children.length > 0) {
self.contentArea.removeChild(self.contentArea.children[0]);
}
var yPos = 0;
var hasItems = false;
for (var item in inventory) {
if (inventory[item] > 0) {
hasItems = true;
var sellItemContainer = new Container();
// Item sprite
var itemSprite = LK.getAsset(item, {
anchorX: 0.5,
anchorY: 0.5,
width: 40,
height: 40
});
itemSprite.x = -150;
sellItemContainer.addChild(itemSprite);
// Item info text
var itemValue = getItemValue(item);
var totalValue = inventory[item] * itemValue;
var infoText = new Text2(item + ' x' + inventory[item] + ' = ' + totalValue + ' coins', {
size: 20,
fill: 0xFFFFFF
});
infoText.anchor.set(0, 0.5);
infoText.x = -100;
sellItemContainer.addChild(infoText);
// Sell button for this item
var sellItemButton = new Container();
var sellItemBg = sellItemButton.attachAsset('inventorySlot', {
anchorX: 0.5,
anchorY: 0.5,
width: 80,
height: 40
});
var sellItemText = new Text2('Sell', {
size: 18,
fill: 0xFFFFFF
});
sellItemText.anchor.set(0.5, 0.5);
sellItemButton.addChild(sellItemText);
sellItemButton.x = 200;
sellItemContainer.addChild(sellItemButton);
// Create closure for button handler
(function (itemType) {
sellItemButton.down = function (x, y, obj) {
sellItemBg.tint = 0x666666;
// Sell this item type
if (inventory[itemType] > 0) {
var value = inventory[itemType] * getItemValue(itemType);
LK.setScore(LK.getScore() + value);
inventory[itemType] = 0;
// Flash effect
tween(sellItemButton, {
alpha: 0.5
}, {
duration: 200,
onFinish: function onFinish() {
tween(sellItemButton, {
alpha: 1
}, {
duration: 200
});
}
});
// Refresh the selling interface
LK.setTimeout(function () {
self.showSellingInterface();
}, 400);
}
};
sellItemButton.up = function (x, y, obj) {
sellItemBg.tint = 0xFFFFFF;
};
})(item);
sellItemContainer.y = yPos;
self.contentArea.addChild(sellItemContainer);
yPos += 60;
}
}
if (!hasItems) {
var noItemsText = new Text2('No items to sell!', {
size: 24,
fill: 0xFFFFFF
});
noItemsText.anchor.set(0.5, 0.5);
self.contentArea.addChild(noItemsText);
}
};
self.visible = false;
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5,
width: 64,
height: 64
});
var playerVerticalGraphics = self.attachAsset('playerVertical', {
anchorX: 0.5,
anchorY: 0.5,
width: 64,
height: 64
});
playerVerticalGraphics.visible = false; // Hide vertical sprite initially
var playerDownGraphics = self.attachAsset('playerDown', {
anchorX: 0.5,
anchorY: 0.5,
width: 64,
height: 64
});
playerDownGraphics.visible = false; // Hide down sprite initially
self.maxHealth = 100;
self.health = self.maxHealth;
self.speed = 3;
self.attackRange = 80;
self.attackDamage = 25;
self.lastAttackTime = 0;
self.attackCooldown = 500;
self.facingDirection = 'right'; // Track which direction player is facing
self.lastX = 0; // Track last position to determine movement direction
self.lastY = 0;
// Method to update sprite direction based on facing
self.updateSpriteDirection = function () {
if (self.facingDirection === 'left') {
playerGraphics.visible = true;
playerVerticalGraphics.visible = false;
playerDownGraphics.visible = false;
playerGraphics.scale.x = -1; // Flip sprite horizontally
playerGraphics.rotation = 0; // No rotation
} else if (self.facingDirection === 'right') {
playerGraphics.visible = true;
playerVerticalGraphics.visible = false;
playerDownGraphics.visible = false;
playerGraphics.scale.x = 1; // Normal sprite orientation
playerGraphics.rotation = 0; // No rotation
} else if (self.facingDirection === 'up') {
playerGraphics.visible = false;
playerVerticalGraphics.visible = true;
playerDownGraphics.visible = false;
playerVerticalGraphics.scale.x = 1; // Normal scale
playerVerticalGraphics.rotation = 0; // No rotation - use original up sprite
} else if (self.facingDirection === 'down') {
playerGraphics.visible = false;
playerVerticalGraphics.visible = false;
playerDownGraphics.visible = true;
playerDownGraphics.scale.x = 1; // Normal scale
playerDownGraphics.rotation = 0; // No rotation - use separate down sprite
}
};
// Method to set facing direction and update sprite
self.setFacingDirection = function (direction) {
if (direction === 'left' || direction === 'right' || direction === 'up' || direction === 'down') {
self.facingDirection = direction;
self.updateSpriteDirection();
}
};
self.takeDamage = function (damage) {
self.health -= damage;
if (self.health <= 0) {
self.health = 0;
LK.showGameOver();
}
LK.effects.flashObject(self, 0xFF0000, 300);
LK.getSound('hurt').play();
};
self.heal = function (amount) {
self.health = Math.min(self.maxHealth, self.health + amount);
};
self.canAttack = function () {
return LK.ticks - self.lastAttackTime > self.attackCooldown;
};
self.canMoveTo = function (x, y) {
return !checkCollisionWithSolids(x, y, 15);
};
self.update = function () {
// Detect movement direction and update facing
if (self.x !== self.lastX) {
if (self.x > self.lastX) {
self.setFacingDirection('right');
} else if (self.x < self.lastX) {
self.setFacingDirection('left');
}
} else if (self.y !== self.lastY) {
if (self.y > self.lastY) {
self.setFacingDirection('down');
} else if (self.y < self.lastY) {
self.setFacingDirection('up');
}
}
// Update last position for next frame
self.lastX = self.x;
self.lastY = self.y;
};
self.attack = function () {
if (!self.canAttack()) return;
self.lastAttackTime = LK.ticks;
LK.getSound('attack').play();
// Check for slimes in attack range with line of sight
for (var i = 0; i < slimes.length; i++) {
var slime = slimes[i];
var dx = slime.x - self.x;
var dy = slime.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= self.attackRange && hasLineOfSight(self.x, self.y, slime.x, slime.y)) {
slime.takeDamage(self.attackDamage);
}
}
// Check for rocks in attack range with line of sight
for (var i = 0; i < rocks.length; i++) {
var rock = rocks[i];
var dx = rock.x - self.x;
var dy = rock.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= self.attackRange && hasLineOfSight(self.x, self.y, rock.x, rock.y)) {
rock.hit();
}
}
};
return self;
});
var Resource = Container.expand(function (type) {
var self = Container.call(this);
self.type = type;
self.collected = false;
var resourceGraphics = self.attachAsset(type, {
anchorX: 0.5,
anchorY: 0.5,
width: 32,
height: 32
});
self.collect = function () {
if (self.collected) return;
self.collected = true;
LK.getSound('collect').play();
// Update inventory
if (!inventory[self.type]) {
inventory[self.type] = 0;
}
inventory[self.type]++;
// Remove from resources array
for (var i = resources.length - 1; i >= 0; i--) {
if (resources[i] === self) {
resources.splice(i, 1);
break;
}
}
game.removeChild(self);
};
return self;
});
var Rock = Container.expand(function (rockType) {
var self = Container.call(this);
self.rockType = rockType || 'rock';
var rockGraphics = self.attachAsset(self.rockType, {
anchorX: 0.5,
anchorY: 0.5,
width: 64,
height: 64
});
self.maxHealth = 3;
self.health = self.maxHealth;
self.destroyed = false;
self.mined = false;
self.hit = function () {
if (self.destroyed) return;
self.health--;
LK.getSound('mine_hit').play();
LK.effects.flashObject(self, 0xFFFFFF, 200);
if (self.health <= 0) {
self.mine();
}
};
self.mine = function () {
if (self.mined || self.destroyed) return;
self.mined = true;
// Animate to half size and make collectable
tween(rockGraphics, {
width: 32,
height: 32
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
// Now it becomes a collectable resource
self.collectable = true;
// If this rock has the ladder, reveal it underneath
if (self.hasLadder && !ladder) {
ladder = new Ladder();
ladder.x = self.x;
ladder.y = self.y;
game.addChild(ladder);
}
}
});
};
self.destroy = function () {
if (self.destroyed) return;
self.destroyed = true;
// Drop resources based on rock type
var resource;
if (self.rockType === 'coal') {
resource = new Resource('coal');
} else if (self.rockType === 'copper_ore') {
resource = new Resource('copper_ore');
} else if (self.rockType === 'iron_ore') {
resource = new Resource('iron_ore');
} else if (self.rockType === 'gold_ore') {
resource = new Resource('gold_ore');
} else if (self.rockType === 'gem') {
resource = new Resource('gem');
} else {
// Regular rock always drops a rock resource
resource = new Resource('rock');
}
if (resource) {
resource.x = self.x;
resource.y = self.y;
resources.push(resource);
game.addChild(resource);
}
// Ladder is now spawned when mining the pre-determined ladder rock, not randomly on destroy
// Remove from rocks array
for (var i = rocks.length - 1; i >= 0; i--) {
if (rocks[i] === self) {
rocks.splice(i, 1);
break;
}
}
game.removeChild(self);
};
self.collect = function () {
if (!self.collectable || self.destroyed) return;
LK.getSound('collect').play();
// Update inventory
if (!inventory[self.rockType]) {
inventory[self.rockType] = 0;
}
inventory[self.rockType]++;
self.destroy();
};
return self;
});
var Slime = Container.expand(function () {
var self = Container.call(this);
var slimeGraphics = self.attachAsset('slime', {
anchorX: 0.5,
anchorY: 0.5,
width: 64,
height: 64
});
self.maxHealth = 100;
self.health = self.maxHealth;
self.speed = 1;
self.attackDamage = 15;
self.lastAttackTime = 0;
self.attackCooldown = 1000;
self.attackRange = 50;
self.lastDamageTime = 0;
self.damageInterval = 100; // 0.1 seconds between damage ticks
self.destroyed = false;
self.takeDamage = function (damage) {
if (self.destroyed) return;
self.health -= damage;
LK.effects.flashObject(self, 0xFF0000, 200);
if (self.health <= 0) {
self.destroy();
}
};
self.destroy = function () {
if (self.destroyed) return;
self.destroyed = true;
// Always drop slime item
var slimeResource = new Resource('slime');
slimeResource.x = self.x;
slimeResource.y = self.y;
resources.push(slimeResource);
game.addChild(slimeResource);
// Drop heart sometimes
if (Math.random() < 0.3) {
var heart = new HealthItem();
heart.x = self.x;
heart.y = self.y;
healthItems.push(heart);
game.addChild(heart);
}
// Remove from slimes array
for (var i = slimes.length - 1; i >= 0; i--) {
if (slimes[i] === self) {
slimes.splice(i, 1);
break;
}
}
// Increase score
LK.setScore(LK.getScore() + 10);
game.removeChild(self);
};
self.update = function () {
if (self.destroyed) return;
// Check if player is visible (line of sight)
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (hasLineOfSight(self.x, self.y, player.x, player.y) && distance < 300) {
// Move towards player if visible and within detection range in any direction (including diagonals)
var moveX = dx / distance * self.speed;
var moveY = dy / distance * self.speed;
var newX = self.x + moveX;
var newY = self.y + moveY;
// Check collision before moving (only with solids and other slimes, not player)
if (!checkCollisionWithSolids(newX, newY, 15) && !checkCollisionWithSlimes(newX, newY, 15, self)) {
self.x = newX;
self.y = newY;
}
// Apply damage if touching player in any direction (including diagonals)
if (distance <= 50 && LK.ticks - self.lastDamageTime > self.damageInterval) {
self.lastDamageTime = LK.ticks;
player.takeDamage(Math.floor(player.maxHealth * 0.05)); // 5% damage
}
}
};
return self;
});
var ToolMerchant = Container.expand(function () {
var self = Container.call(this);
var npcGraphics = self.attachAsset('toolMerchantNPC', {
anchorX: 0.5,
anchorY: 0.5,
width: 192,
height: 192
});
self.down = function (x, y, obj) {
// Open tool merchant interface
if (toolMerchantInterface) {
toolMerchantInterface.visible = true;
}
};
return self;
});
var ToolMerchantInterface = Container.expand(function () {
var self = Container.call(this);
// Create background panel
var background = self.attachAsset('inventoryBackground', {
anchorX: 0.5,
anchorY: 0.5,
width: 800,
height: 600
});
// Create border
var border = self.attachAsset('inventoryBorder', {
anchorX: 0.5,
anchorY: 0.5,
width: 820,
height: 620
});
self.addChildAt(border, 0);
// Title text
var titleText = new Text2('Tool Shop', {
size: 40,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0);
titleText.x = 0;
titleText.y = -280;
self.addChild(titleText);
// Content area for tools
self.contentArea = new Container();
self.contentArea.y = -100;
self.addChild(self.contentArea);
// Close button
var closeButton = new Container();
var closeBg = closeButton.attachAsset('inventoryButton', {
anchorX: 0.5,
anchorY: 0.5
});
var closeText = new Text2('X', {
size: 30,
fill: 0xFF0000
});
closeText.anchor.set(0.5, 0.5);
closeButton.addChild(closeText);
closeButton.x = 350;
closeButton.y = -250;
self.addChild(closeButton);
closeButton.down = function (x, y, obj) {
closeBg.tint = 0x666666;
self.visible = false;
};
closeButton.up = function (x, y, obj) {
closeBg.tint = 0xFFFFFF;
};
// Show available tools
self.showTools = function () {
// Clear content area
while (self.contentArea.children.length > 0) {
self.contentArea.removeChild(self.contentArea.children[0]);
}
var tools = [{
item: 'pickaxe',
material: 'Stone',
price: 10
}, {
item: 'pickaxe',
material: 'Copper',
price: 25
}, {
item: 'pickaxe',
material: 'Iron',
price: 50
}, {
item: 'pickaxe',
material: 'Gold',
price: 100
}, {
item: 'sword',
material: 'Stone',
price: 15
}, {
item: 'sword',
material: 'Copper',
price: 30
}, {
item: 'sword',
material: 'Iron',
price: 60
}, {
item: 'sword',
material: 'Gold',
price: 120
}];
var yPos = 0;
for (var i = 0; i < tools.length; i++) {
var toolContainer = new Container();
// Tool sprite
var toolSprite = LK.getAsset(tools[i].item, {
anchorX: 0.5,
anchorY: 0.5,
width: 40,
height: 40
});
toolSprite.x = -150;
// Apply material tint
if (tools[i].material === 'Copper') {
toolSprite.tint = 0xB87333;
} else if (tools[i].material === 'Iron') {
toolSprite.tint = 0x778899;
} else if (tools[i].material === 'Gold') {
toolSprite.tint = 0xFFD700;
} else {
toolSprite.tint = 0x808080; // Stone
}
toolContainer.addChild(toolSprite);
// Tool info text
var infoText = new Text2(tools[i].material + ' ' + tools[i].item + ' - ' + tools[i].price + ' coins', {
size: 20,
fill: 0xFFFFFF
});
infoText.anchor.set(0, 0.5);
infoText.x = -100;
toolContainer.addChild(infoText);
// Buy button
var buyButton = new Container();
var buyBg = buyButton.attachAsset('inventorySlot', {
anchorX: 0.5,
anchorY: 0.5,
width: 80,
height: 40
});
var buyText = new Text2('Buy', {
size: 18,
fill: 0xFFFFFF
});
buyText.anchor.set(0.5, 0.5);
buyButton.addChild(buyText);
buyButton.x = 200;
toolContainer.addChild(buyButton);
// Create closure for button handler
(function (tool) {
buyButton.down = function (x, y, obj) {
buyBg.tint = 0x666666;
// Check if player has enough coins
var currentCoins = LK.getScore();
if (currentCoins >= tool.price) {
// Deduct coins
LK.setScore(currentCoins - tool.price);
// Add tool to inventory
if (!inventory[tool.material.toLowerCase() + '_' + tool.item]) {
inventory[tool.material.toLowerCase() + '_' + tool.item] = 0;
}
inventory[tool.material.toLowerCase() + '_' + tool.item]++;
// Flash effect
tween(buyButton, {
alpha: 0.5
}, {
duration: 200,
onFinish: function onFinish() {
tween(buyButton, {
alpha: 1
}, {
duration: 200
});
}
});
} else {
// Not enough coins - flash red
tween(buyButton, {
tint: 0xFF0000
}, {
duration: 200,
onFinish: function onFinish() {
tween(buyButton, {
tint: 0xFFFFFF
}, {
duration: 200
});
}
});
}
};
buyButton.up = function (x, y, obj) {
buyBg.tint = 0xFFFFFF;
};
})(tools[i]);
toolContainer.y = yPos;
self.contentArea.addChild(toolContainer);
yPos += 60;
}
};
// Initialize with tools display
self.showTools();
self.visible = false;
return self;
});
var Wall = Container.expand(function () {
var self = Container.call(this);
var wallGraphics = self.attachAsset('wall', {
anchorX: 0.5,
anchorY: 0.5,
width: 64,
height: 64
});
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2F1B14
});
/****
* Game Code
****/
var player;
var rocks = [];
var slimes = [];
var resources = [];
var healthItems = [];
var ladder;
var inventory = {};
var currentFloor = 0; // Start at floor 0 (surface)
var walls = [];
var floorTiles = [];
var inventoryInterface;
var inventoryButton;
var merchant;
var forestObjects = [];
var merchantInterface;
var isInMine = false;
var locationStatus;
var coinDisplay;
var toolMerchant;
var toolMerchantInterface;
function checkCollisionWithWalls(x, y, radius) {
for (var i = 0; i < walls.length; i++) {
var wall = walls[i];
var dx = Math.abs(x - wall.x);
var dy = Math.abs(y - wall.y);
if (dx < 32 + radius && dy < 32 + radius) {
return true;
}
}
return false;
}
function checkCollisionWithSolids(x, y, radius) {
// Check collision with walls
for (var i = 0; i < walls.length; i++) {
var wall = walls[i];
var dx = Math.abs(x - wall.x);
var dy = Math.abs(y - wall.y);
if (dx < 32 + radius && dy < 32 + radius) {
return true;
}
}
// Check collision with rocks
for (var i = 0; i < rocks.length; i++) {
var rock = rocks[i];
if (!rock.destroyed && !rock.mined) {
var dx = Math.abs(x - rock.x);
var dy = Math.abs(y - rock.y);
if (dx < 16 + radius && dy < 16 + radius) {
return true;
}
}
}
// Check collision with forest objects (trees and bushes)
for (var i = 0; i < forestObjects.length; i++) {
var forestObj = forestObjects[i];
var dx = Math.abs(x - forestObj.x);
var dy = Math.abs(y - forestObj.y);
var objRadius = forestObj.width > 64 ? 48 : 24; // Trees are bigger
if (dx < objRadius + radius && dy < objRadius + radius) {
return true;
}
}
return false;
}
function checkCollisionWithSlimes(x, y, radius, excludeSlime) {
for (var i = 0; i < slimes.length; i++) {
var slime = slimes[i];
if (!slime.destroyed && slime !== excludeSlime) {
var dx = Math.abs(x - slime.x);
var dy = Math.abs(y - slime.y);
if (dx < 50 + radius && dy < 50 + radius) {
return true;
}
}
}
return false;
}
function checkCollisionWithPlayer(x, y, radius) {
if (!player) return false;
var dx = Math.abs(x - player.x);
var dy = Math.abs(y - player.y);
if (dx < 32 + radius && dy < 32 + radius) {
return true;
}
return false;
}
function hasLineOfSight(x1, y1, x2, y2) {
var dx = x2 - x1;
var dy = y2 - y1;
var distance = Math.sqrt(dx * dx + dy * dy);
var steps = Math.floor(distance / 16);
for (var i = 0; i <= steps; i++) {
var checkX = x1 + dx * i / steps;
var checkY = y1 + dy * i / steps;
if (checkCollisionWithSolids(checkX, checkY, 8)) {
return false;
}
}
return true;
}
// UI Elements
var healthBar;
var floorText;
var inventoryText;
function initializeGame() {
player = game.addChild(new Player());
if (currentFloor === 0) {
player.x = 1024;
player.y = 400; // Start on surface near cave entrance
} else {
player.x = 1024;
player.y = 300; // Start in mine near entrance
}
// Initialize position tracking
player.lastX = player.x;
player.lastY = player.y;
// Create UI - Health bar as horizontal bar (larger)
healthBar = new Container();
var healthBarBg = healthBar.attachAsset('wall', {
anchorX: 0,
anchorY: 0,
width: 400,
height: 30
});
healthBarBg.tint = 0x333333; // Dark background
var healthBarFill = healthBar.attachAsset('wall', {
anchorX: 0,
anchorY: 0,
width: 396,
height: 26
});
healthBarFill.tint = 0xFF0000; // Red health fill
healthBarFill.x = 2;
healthBarFill.y = 2;
healthBar.healthBarFill = healthBarFill; // Store reference for updates
LK.gui.topLeft.addChild(healthBar);
healthBar.x = 130;
healthBar.y = 20;
floorText = new Container();
var floorSprite = floorText.attachAsset('ladder', {
anchorX: 0,
anchorY: 0,
width: 40,
height: 40
});
floorText.floorSprite = floorSprite; // Store reference for updates
var floorNumber = new Text2('1', {
size: 40,
fill: 0xFFFFFF
});
floorNumber.anchor.set(0, 0);
floorNumber.x = 50;
floorNumber.y = 0;
floorText.addChild(floorNumber);
floorText.floorNumber = floorNumber; // Store reference for updates
var locationText = new Text2('', {
size: 30,
fill: 0xFFFFFF
});
locationText.anchor.set(0, 0);
locationText.x = 100;
locationText.y = 5;
floorText.addChild(locationText);
floorText.locationText = locationText; // Store reference for updates
LK.gui.top.addChild(floorText);
floorText.y = 20;
// Create location status indicator next to floor indicator
locationStatus = new Container();
var locationSprite = locationStatus.attachAsset('locationTown', {
anchorX: 0,
anchorY: 0,
width: 40,
height: 40
});
locationStatus.locationSprite = locationSprite; // Store reference for updates
var locationStatusText = new Text2('pueblo', {
size: 30,
fill: 0xFFFFFF
});
locationStatusText.anchor.set(0, 0);
locationStatusText.x = 50;
locationStatusText.y = 5;
locationStatus.addChild(locationStatusText);
locationStatus.locationStatusText = locationStatusText; // Store reference for updates
LK.gui.top.addChild(locationStatus);
locationStatus.x = 200; // Position to the right of floor indicator
locationStatus.y = 20;
// Create coin display next to location status
coinDisplay = new Container();
var coinSprite = coinDisplay.attachAsset('coin', {
anchorX: 0,
anchorY: 0,
width: 40,
height: 40
});
var coinText = new Text2('0', {
size: 30,
fill: 0xFFD700
});
coinText.anchor.set(0, 0);
coinText.x = 50;
coinText.y = 5;
coinDisplay.addChild(coinText);
coinDisplay.coinText = coinText; // Store reference for updates
LK.gui.top.addChild(coinDisplay);
coinDisplay.x = 400; // Position to the right of location status
coinDisplay.y = 20;
// Create inventory button
inventoryButton = new InventoryButton();
inventoryButton.x = -80;
inventoryButton.y = 80;
LK.gui.topRight.addChild(inventoryButton);
// Create inventory interface (initially hidden)
inventoryInterface = new InventoryInterface();
inventoryInterface.x = 0;
inventoryInterface.y = 0;
LK.gui.center.addChild(inventoryInterface);
// Create merchant interface (initially hidden)
merchantInterface = new MerchantInterface();
merchantInterface.x = 0;
merchantInterface.y = 0;
LK.gui.center.addChild(merchantInterface);
// Create tool merchant interface (initially hidden)
toolMerchantInterface = new ToolMerchantInterface();
toolMerchantInterface.x = 0;
toolMerchantInterface.y = 0;
LK.gui.center.addChild(toolMerchantInterface);
generateFloor();
// Create directional control buttons in bottom left
var buttonSize = 80;
var buttonSpacing = 90;
var baseX = 120;
var baseY = -200;
// Create up arrow button
var upButton = new DirectionalButton('Up');
upButton.x = baseX;
upButton.y = baseY - buttonSpacing;
LK.gui.bottomLeft.addChild(upButton);
// Create down arrow button
var downButton = new DirectionalButton('Down');
downButton.x = baseX;
downButton.y = baseY + buttonSpacing;
LK.gui.bottomLeft.addChild(downButton);
// Create left arrow button
var leftButton = new DirectionalButton('Left');
leftButton.x = baseX - buttonSpacing;
leftButton.y = baseY;
LK.gui.bottomLeft.addChild(leftButton);
// Create right arrow button
var rightButton = new DirectionalButton('Right');
rightButton.x = baseX + buttonSpacing;
rightButton.y = baseY;
LK.gui.bottomLeft.addChild(rightButton);
// Create action buttons on the right side
var actionBaseX = -120;
var actionBaseY = -200;
// Create pickaxe button
var pickaxeButton = new ActionButton('pickaxe');
pickaxeButton.x = actionBaseX;
pickaxeButton.y = actionBaseY - buttonSpacing / 2;
LK.gui.bottomRight.addChild(pickaxeButton);
// Create sword button
var swordButton = new ActionButton('sword');
swordButton.x = actionBaseX;
swordButton.y = actionBaseY + buttonSpacing / 2;
LK.gui.bottomRight.addChild(swordButton);
}
function generateFloor() {
// Clear existing objects
clearFloor();
if (currentFloor === 0) {
// Generate surface floor (floor 0)
generateSurface();
return;
}
// Generate floor tiles for grid visualization
for (var x = 64; x < 2048; x += 64) {
for (var y = 196; y < 2700; y += 64) {
var floorTile = new FloorTile();
floorTile.x = x;
floorTile.y = y;
floorTiles.push(floorTile);
game.addChild(floorTile);
}
}
// Generate perimeter walls
for (var x = 0; x < 2048; x += 64) {
var topWall = new Wall();
topWall.x = x + 32;
topWall.y = 132;
walls.push(topWall);
game.addChild(topWall);
var bottomWall = new Wall();
bottomWall.x = x + 32;
bottomWall.y = 2700;
walls.push(bottomWall);
game.addChild(bottomWall);
}
for (var y = 132; y < 2700; y += 64) {
var leftWall = new Wall();
leftWall.x = 32;
leftWall.y = y + 32;
walls.push(leftWall);
game.addChild(leftWall);
var rightWall = new Wall();
rightWall.x = 2016;
rightWall.y = y + 32;
walls.push(rightWall);
game.addChild(rightWall);
}
// Generate structured maze with corridors and chambers
generateMazeStructure();
// Pre-determine which rock will contain the ladder
var ladderRockIndex = Math.floor(Math.random() * (15 + Math.floor(currentFloor * 2)));
var ladderRock = null;
// Generate rocks with different types based on floor, placed in accessible areas
var numRocks = 15 + Math.floor(currentFloor * 2);
for (var i = 0; i < numRocks; i++) {
var rockType = 'rock'; // Default rock type
var rand = Math.random();
// Higher floors have better chances for rare materials
var floorMultiplier = Math.min(currentFloor / 10, 1); // Cap at floor 10
if (rand < 0.3) {
rockType = 'coal'; // Common on all floors
} else if (rand < 0.3 + 0.2 * floorMultiplier) {
rockType = 'copper_ore'; // More common on higher floors
} else if (rand < 0.3 + 0.2 * floorMultiplier + 0.15 * floorMultiplier) {
rockType = 'iron_ore'; // Rare, more common on higher floors
} else if (rand < 0.3 + 0.2 * floorMultiplier + 0.15 * floorMultiplier + 0.1 * floorMultiplier) {
rockType = 'gold_ore'; // Very rare, much more common on higher floors
} else if (rand < 0.3 + 0.2 * floorMultiplier + 0.15 * floorMultiplier + 0.1 * floorMultiplier + 0.05 * floorMultiplier) {
rockType = 'gem'; // Extremely rare, only on higher floors
}
var rock = new Rock(rockType);
var attempts = 0;
do {
// Generate grid-aligned positions (64x64 grid cells)
var gridX = Math.floor(Math.random() * 26) + 3; // Grid positions 3-28
var gridY = Math.floor(Math.random() * 32) + 5; // Grid positions 5-36
rock.x = 64 + gridX * 64; // Center in grid cell
rock.y = 196 + gridY * 64; // Center in grid cell
attempts++;
} while (checkCollisionWithSolids(rock.x, rock.y, 24) && attempts < 100);
// If we couldn't find a good spot after 100 attempts, place it along corridors
if (attempts >= 100) {
var corridorGridX = Math.floor(Math.random() * 18) + 6; // Corridor area grid
var corridorGridY = Math.floor(Math.random() * 20) + 9; // Corridor area grid
rock.x = 64 + corridorGridX * 64;
rock.y = 196 + corridorGridY * 64;
// Try a few more times in corridor area
var corridorAttempts = 0;
while (checkCollisionWithSolids(rock.x, rock.y, 24) && corridorAttempts < 20) {
corridorGridX = Math.floor(Math.random() * 18) + 6;
corridorGridY = Math.floor(Math.random() * 20) + 9;
rock.x = 64 + corridorGridX * 64;
rock.y = 196 + corridorGridY * 64;
corridorAttempts++;
}
}
// Mark this rock as the ladder rock if it's the chosen one
if (i === ladderRockIndex) {
rock.hasLadder = true;
ladderRock = rock;
}
rocks.push(rock);
game.addChild(rock);
}
// Generate slimes in accessible areas
var numSlimes = 3 + Math.floor(currentFloor * 1.5);
for (var i = 0; i < numSlimes; i++) {
var slime = new Slime();
var attempts = 0;
do {
slime.x = 200 + Math.random() * 1648;
slime.y = 300 + Math.random() * 2132;
attempts++;
} while (checkCollisionWithSolids(slime.x, slime.y, 20) && attempts < 100);
// If we couldn't find a good spot after 100 attempts, place it along corridors
if (attempts >= 100) {
slime.x = 400 + Math.random() * 1200;
slime.y = 600 + Math.random() * 1400;
// Try a few more times in corridor area
var corridorAttempts = 0;
while (checkCollisionWithSolids(slime.x, slime.y, 20) && corridorAttempts < 20) {
slime.x = 400 + Math.random() * 1200;
slime.y = 600 + Math.random() * 1400;
corridorAttempts++;
}
}
slime.maxHealth += Math.floor(currentFloor * 10);
slime.health = slime.maxHealth;
slimes.push(slime);
game.addChild(slime);
}
// Create portal at the top center (to return to surface)
var portal = LK.getAsset('portalEntrance', {
anchorX: 0.5,
anchorY: 0.5,
width: 192,
height: 192
});
portal.x = 1024; // Center horizontally
portal.y = 300; // Consistent position with surface
portal.isPortal = true;
game.addChild(portal);
// Ladder will be generated when mining rocks
ladder = null;
// Update floor text and sprite based on location
if (currentFloor === 0) {
// On surface - use tree sprite and show "Pueblo Pochis"
floorText.removeChild(floorText.floorSprite);
floorText.floorSprite = floorText.attachAsset('tree', {
anchorX: 0,
anchorY: 0,
width: 40,
height: 40
});
floorText.addChildAt(floorText.floorSprite, 0);
floorText.floorNumber.setText('0');
floorText.locationText.setText('Pueblo Pochis');
// Update location status indicator
locationStatus.removeChild(locationStatus.locationSprite);
locationStatus.locationSprite = locationStatus.attachAsset('locationTown', {
anchorX: 0,
anchorY: 0,
width: 40,
height: 40
});
locationStatus.addChildAt(locationStatus.locationSprite, 0);
locationStatus.locationStatusText.setText('pueblo');
} else {
// In mine - use ladder sprite and show floor number
floorText.removeChild(floorText.floorSprite);
floorText.floorSprite = floorText.attachAsset('ladder', {
anchorX: 0,
anchorY: 0,
width: 40,
height: 40
});
floorText.addChildAt(floorText.floorSprite, 0);
floorText.floorNumber.setText(currentFloor.toString());
floorText.locationText.setText('');
// Update location status indicator
locationStatus.removeChild(locationStatus.locationSprite);
locationStatus.locationSprite = locationStatus.attachAsset('locationMine', {
anchorX: 0,
anchorY: 0,
width: 40,
height: 40
});
locationStatus.addChildAt(locationStatus.locationSprite, 0);
locationStatus.locationStatusText.setText('minas');
}
}
function clearFloor() {
// Remove all floor tiles
for (var i = 0; i < floorTiles.length; i++) {
game.removeChild(floorTiles[i]);
}
floorTiles = [];
// Remove all walls
for (var i = 0; i < walls.length; i++) {
game.removeChild(walls[i]);
}
walls = [];
// Remove all rocks
for (var i = 0; i < rocks.length; i++) {
game.removeChild(rocks[i]);
}
rocks = [];
// Remove all slimes
for (var i = 0; i < slimes.length; i++) {
game.removeChild(slimes[i]);
}
slimes = [];
// Remove all resources
for (var i = 0; i < resources.length; i++) {
game.removeChild(resources[i]);
}
resources = [];
// Remove all health items
for (var i = 0; i < healthItems.length; i++) {
game.removeChild(healthItems[i]);
}
healthItems = [];
// Remove ladder
if (ladder) {
game.removeChild(ladder);
ladder = null;
}
// Remove forest objects
for (var i = 0; i < forestObjects.length; i++) {
game.removeChild(forestObjects[i]);
}
forestObjects = [];
// Remove merchant
if (merchant) {
game.removeChild(merchant);
merchant = null;
}
// Remove tool merchant
if (toolMerchant) {
game.removeChild(toolMerchant);
toolMerchant = null;
}
}
function updateInventoryInterface() {
// Clear existing items from slots
for (var i = 0; i < inventoryInterface.itemSlots.length; i++) {
var slot = inventoryInterface.itemSlots[i];
// Remove all children except the background (first child)
while (slot.children.length > 1) {
slot.removeChild(slot.children[slot.children.length - 1]);
}
}
// Add items to slots
var slotIndex = 0;
for (var item in inventory) {
if (inventory[item] > 0 && slotIndex < inventoryInterface.itemSlots.length) {
var slot = inventoryInterface.itemSlots[slotIndex];
// Add item sprite
var itemSprite = LK.getAsset(item, {
anchorX: 0.5,
anchorY: 0.5,
width: 50,
height: 50
});
itemSprite.x = 0;
itemSprite.y = -10;
slot.addChild(itemSprite);
// Add quantity text
var quantityText = new Text2(inventory[item].toString(), {
size: 20,
fill: 0xFFFFFF
});
quantityText.anchor.set(0.5, 0);
quantityText.x = 0;
quantityText.y = 20;
slot.addChild(quantityText);
slotIndex++;
}
}
}
function updateUI() {
// Update health bar - scale the fill based on health percentage (horizontal)
var healthPercent = player.health / player.maxHealth;
healthBar.healthBarFill.width = 396 * healthPercent;
// Change health bar color based on percentage
if (healthPercent > 0.66) {
tween(healthBar.healthBarFill, {
tint: 0x00FF00
}, {
duration: 200
}); // Green for healthy
} else if (healthPercent > 0.33) {
tween(healthBar.healthBarFill, {
tint: 0xFFFF00
}, {
duration: 200
}); // Yellow for medium health
} else {
tween(healthBar.healthBarFill, {
tint: 0xFF0000
}, {
duration: 200
}); // Red for low health
}
// Update coin display
if (coinDisplay && coinDisplay.coinText) {
coinDisplay.coinText.setText(LK.getScore().toString());
}
// Inventory is now handled by the inventory interface when opened
}
var dragNode = null;
function handleMove(x, y, obj) {
if (dragNode) {
var newX = x;
var newY = y;
// Keep player within bounds
newX = Math.max(64, Math.min(1984, newX));
newY = Math.max(164, Math.min(2668, newY));
// Check collision with walls and rocks
if (!checkCollisionWithSolids(newX, newY, 15)) {
var oldX = dragNode.x;
dragNode.x = newX;
dragNode.y = newY;
// Update player facing direction based on drag movement
if (dragNode === player) {
var oldY = dragNode.y;
if (newX !== oldX) {
if (newX > oldX) {
player.setFacingDirection('right');
} else if (newX < oldX) {
player.setFacingDirection('left');
}
} else if (newY !== oldY) {
if (newY > oldY) {
player.setFacingDirection('down');
} else if (newY < oldY) {
player.setFacingDirection('up');
}
}
}
}
}
}
game.move = handleMove;
game.down = function (x, y, obj) {
dragNode = player;
handleMove(x, y, obj);
};
game.up = function (x, y, obj) {
dragNode = null;
};
game.update = function () {
if (!player) return;
// Update player
player.update();
// Update slimes
for (var i = 0; i < slimes.length; i++) {
slimes[i].update();
}
// Slimes now handle their own damage timing individually
// Automatic mining removed - now controlled by left click
// Check resource collection
for (var i = resources.length - 1; i >= 0; i--) {
var resource = resources[i];
var dx = resource.x - player.x;
var dy = resource.y - player.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 40) {
resource.collect();
}
}
// Check mined rock collection
for (var i = rocks.length - 1; i >= 0; i--) {
var rock = rocks[i];
if (rock.collectable && !rock.destroyed) {
var dx = rock.x - player.x;
var dy = rock.y - player.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 40) {
rock.collect();
}
}
}
// Check health item collection
for (var i = healthItems.length - 1; i >= 0; i--) {
var healthItem = healthItems[i];
var dx = healthItem.x - player.x;
var dy = healthItem.y - player.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 40) {
healthItem.collect();
}
}
// Check ladder interaction (only in mine floors)
if (ladder && !ladder.used && currentFloor > 0) {
var dx = ladder.x - player.x;
var dy = ladder.y - player.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 50) {
ladder.use();
}
}
// Check portal interactions
var allChildren = game.children;
for (var i = 0; i < allChildren.length; i++) {
var child = allChildren[i];
if (child.isPortal) {
var dx = child.x - player.x;
var dy = child.y - player.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 100) {
if (currentFloor === 0) {
// Enter mine (go to floor 1)
currentFloor = 1;
isInMine = true;
generateFloor();
// Spawn player 4 blocks (256 pixels) below the portal
player.x = 1024;
player.y = 300 + 256;
} else {
// Exit mine (go to pueblo pochis - floor 0)
currentFloor = 0;
isInMine = false;
generateFloor();
// Spawn player 4 blocks (256 pixels) below the portal
player.x = 1024;
player.y = 300 + 256;
}
break;
}
}
}
// Update UI
updateUI();
};
// Initialize the game
initializeGame();
function generateMazeStructure() {
// Create grid for maze generation (30x38 cells, each cell is 64x64 pixels)
var gridWidth = 30;
var gridHeight = 38;
var cellSize = 64;
var startX = 96;
var startY = 196;
// Create a grid to track where corridors are
var corridorGrid = [];
for (var x = 0; x < gridWidth; x++) {
corridorGrid[x] = [];
for (var y = 0; y < gridHeight; y++) {
corridorGrid[x][y] = false;
}
}
// Create main entrance tunnel from top-center
var entranceX = Math.floor(gridWidth / 2);
for (var y = 2; y < 8; y++) {
corridorGrid[entranceX][y] = true;
// Make entrance wider (3 tiles wide)
if (entranceX - 1 >= 0) corridorGrid[entranceX - 1][y] = true;
if (entranceX + 1 < gridWidth) corridorGrid[entranceX + 1][y] = true;
}
// Create main horizontal distribution corridor
var mainCorridorY = 8;
for (var x = 4; x < gridWidth - 4; x++) {
corridorGrid[x][mainCorridorY] = true;
// Make main corridor wider
corridorGrid[x][mainCorridorY + 1] = true;
}
// Create realistic mining tunnels branching from main corridor
var numMainTunnels = 4 + Math.floor(currentFloor / 3);
var tunnelSpacing = Math.floor((gridWidth - 8) / numMainTunnels);
for (var i = 0; i < numMainTunnels; i++) {
var tunnelX = 4 + i * tunnelSpacing + Math.floor(Math.random() * (tunnelSpacing / 2));
var tunnelLength = 8 + Math.floor(Math.random() * 12);
var tunnelStartY = mainCorridorY + 2;
// Create main mining tunnel going down
for (var y = tunnelStartY; y < Math.min(tunnelStartY + tunnelLength, gridHeight - 2); y++) {
corridorGrid[tunnelX][y] = true;
// Add slight width variation to make it more natural
if (Math.random() > 0.6) {
if (tunnelX - 1 >= 2) corridorGrid[tunnelX - 1][y] = true;
} else if (Math.random() > 0.6) {
if (tunnelX + 1 < gridWidth - 2) corridorGrid[tunnelX + 1][y] = true;
}
}
// Create mining chambers at the end of tunnels
if (tunnelStartY + tunnelLength < gridHeight - 4) {
var chamberY = tunnelStartY + tunnelLength - 2;
var chamberSize = 2 + Math.floor(Math.random() * 2); // 2x2 or 3x3 chamber
for (var cx = -chamberSize; cx <= chamberSize; cx++) {
for (var cy = -1; cy <= chamberSize; cy++) {
var newX = tunnelX + cx;
var newY = chamberY + cy;
if (newX >= 2 && newX < gridWidth - 2 && newY >= 2 && newY < gridHeight - 2) {
corridorGrid[newX][newY] = true;
}
}
}
}
// Create side branches from main tunnels (like real mine shafts)
var numSideBranches = 1 + Math.floor(Math.random() * 2);
for (var j = 0; j < numSideBranches; j++) {
var branchY = tunnelStartY + 3 + Math.floor(Math.random() * (tunnelLength - 6));
var branchDirection = Math.random() > 0.5 ? 1 : -1;
var branchLength = 3 + Math.floor(Math.random() * 5);
for (var k = 1; k <= branchLength; k++) {
var branchX = tunnelX + k * branchDirection;
if (branchX >= 2 && branchX < gridWidth - 2) {
corridorGrid[branchX][branchY] = true;
// Small chamber at end of side branch
if (k === branchLength) {
if (branchY - 1 >= 2) corridorGrid[branchX][branchY - 1] = true;
if (branchY + 1 < gridHeight - 2) corridorGrid[branchX][branchY + 1] = true;
}
}
}
}
}
// Create connecting tunnels between some main tunnels (crosscuts)
var numConnections = Math.floor(numMainTunnels / 2);
for (var i = 0; i < numConnections; i++) {
var connectionY = mainCorridorY + 5 + Math.floor(Math.random() * 10);
var startX = 4 + Math.floor(Math.random() * (gridWidth - 12));
var endX = startX + 4 + Math.floor(Math.random() * 6);
for (var x = startX; x <= Math.min(endX, gridWidth - 3); x++) {
if (connectionY >= 2 && connectionY < gridHeight - 2) {
corridorGrid[x][connectionY] = true;
}
}
}
// Convert corridor grid to walls (fill in non-corridor spaces)
for (var x = 2; x < gridWidth - 2; x++) {
for (var y = 2; y < gridHeight - 2; y++) {
if (!corridorGrid[x][y]) {
var wall = new Wall();
// Align wall to grid cell center (64x64 grid cells)
wall.x = 64 + x * cellSize; // Center in grid cell
wall.y = 196 + y * cellSize; // Center in grid cell
walls.push(wall);
game.addChild(wall);
}
}
}
// Add structural support pillars in wider areas
var numPillars = Math.floor(currentFloor / 3);
for (var i = 0; i < numPillars; i++) {
var pillarX = Math.floor(6 + Math.random() * (gridWidth - 12));
var pillarY = Math.floor(mainCorridorY + 3 + Math.random() * (gridHeight - mainCorridorY - 6));
// Only place pillar if it's in a corridor and won't block paths
if (corridorGrid[pillarX][pillarY]) {
var canPlace = true;
// Check if placing pillar would block critical paths
for (var dx = -1; dx <= 1 && canPlace; dx++) {
for (var dy = -1; dy <= 1 && canPlace; dy++) {
var checkX = pillarX + dx;
var checkY = pillarY + dy;
if (checkX >= 0 && checkX < gridWidth && checkY >= 0 && checkY < gridHeight) {
// Don't place if it would create a dead end
if (!corridorGrid[checkX][checkY] && (dx === 0 || dy === 0)) {
var adjacentCorridors = 0;
if (checkX > 0 && corridorGrid[checkX - 1][checkY]) adjacentCorridors++;
if (checkX < gridWidth - 1 && corridorGrid[checkX + 1][checkY]) adjacentCorridors++;
if (checkY > 0 && corridorGrid[checkX][checkY - 1]) adjacentCorridors++;
if (checkY < gridHeight - 1 && corridorGrid[checkX][checkY + 1]) adjacentCorridors++;
if (adjacentCorridors < 2) canPlace = false;
}
}
}
}
if (canPlace && Math.random() > 0.3) {
var wall = new Wall();
// Align pillar wall to grid cell center (64x64 grid cells)
wall.x = 64 + pillarX * cellSize; // Center in grid cell
wall.y = 196 + pillarY * cellSize; // Center in grid cell
walls.push(wall);
game.addChild(wall);
}
}
}
}
function generateSurface() {
// Generate grass floor tiles
for (var x = 64; x < 2048; x += 64) {
for (var y = 196; y < 2700; y += 64) {
var grassTile = LK.getAsset('grass', {
anchorX: 0.5,
anchorY: 0.5,
width: 64,
height: 64
});
grassTile.x = x;
grassTile.y = y;
grassTile.alpha = 0.7;
floorTiles.push(grassTile);
game.addChild(grassTile);
}
}
// Ensure player renders above grass tiles by moving to front
if (player) {
game.removeChild(player);
game.addChild(player);
}
// Create consistent town layout
// Mine entrance (portal) at the north
var portal = LK.getAsset('portalEntrance', {
anchorX: 0.5,
anchorY: 0.5,
width: 192,
height: 192
});
portal.x = 1024; // Center horizontally
portal.y = 300; // North position
portal.isPortal = true;
game.addChild(portal);
// Create main path from mine to town center (vertical stone path)
var pathTilePositions = [{
x: 1024,
y: 500
}, {
x: 1024,
y: 564
}, {
x: 1024,
y: 628
}, {
x: 1024,
y: 692
}, {
x: 1024,
y: 756
}, {
x: 1024,
y: 820
}, {
x: 1024,
y: 884
}, {
x: 1024,
y: 948
}, {
x: 1024,
y: 1012
}, {
x: 1024,
y: 1076
}, {
x: 1024,
y: 1140
}, {
x: 1024,
y: 1204
}, {
x: 1024,
y: 1268
}, {
x: 1024,
y: 1332
}, {
x: 1024,
y: 1396
}, {
x: 1024,
y: 1460
}];
// Add path tiles
for (var i = 0; i < pathTilePositions.length; i++) {
var pathTile = LK.getAsset('floorTile', {
anchorX: 0.5,
anchorY: 0.5,
width: 64,
height: 64
});
pathTile.x = pathTilePositions[i].x;
pathTile.y = pathTilePositions[i].y;
pathTile.alpha = 0.8;
floorTiles.push(pathTile);
game.addChild(pathTile);
}
// Create houses along the path (consistent positions)
var housePositions = [{
x: 768,
y: 700
},
// Left side house 1
{
x: 1280,
y: 700
},
// Right side house 1
{
x: 768,
y: 900
},
// Left side house 2
{
x: 1280,
y: 900
},
// Right side house 2
{
x: 768,
y: 1100
},
// Left side house 3
{
x: 1280,
y: 1100
},
// Right side house 3
{
x: 768,
y: 1300
},
// Left side house 4
{
x: 1280,
y: 1300
} // Right side house 4
];
// Create houses using wall assets as house blocks
for (var i = 0; i < housePositions.length; i++) {
// Main house structure (3x3 blocks)
for (var hx = -1; hx <= 1; hx++) {
for (var hy = -1; hy <= 1; hy++) {
var houseBlock = LK.getAsset('wall', {
anchorX: 0.5,
anchorY: 0.5,
width: 64,
height: 64
});
houseBlock.x = housePositions[i].x + hx * 64;
houseBlock.y = housePositions[i].y + hy * 64;
houseBlock.tint = 0x8B4513; // Brown color for houses
forestObjects.push(houseBlock);
game.addChild(houseBlock);
}
}
}
// Position NPCs near houses consistently
merchant = new Merchant();
merchant.x = 700; // Near left side houses
merchant.y = 800;
game.addChild(merchant);
toolMerchant = new ToolMerchant();
toolMerchant.x = 1350; // Near right side houses
toolMerchant.y = 800;
game.addChild(toolMerchant);
// Place trees in organized clusters around the town perimeter
var treeClusterPositions = [
// Left forest cluster
{
x: 300,
y: 500
}, {
x: 364,
y: 500
}, {
x: 428,
y: 500
}, {
x: 300,
y: 600
}, {
x: 364,
y: 600
}, {
x: 428,
y: 600
}, {
x: 300,
y: 700
}, {
x: 364,
y: 700
}, {
x: 428,
y: 700
},
// Right forest cluster
{
x: 1620,
y: 500
}, {
x: 1684,
y: 500
}, {
x: 1748,
y: 500
}, {
x: 1620,
y: 600
}, {
x: 1684,
y: 600
}, {
x: 1748,
y: 600
}, {
x: 1620,
y: 700
}, {
x: 1684,
y: 700
}, {
x: 1748,
y: 700
},
// Bottom forest clusters
{
x: 500,
y: 1600
}, {
x: 564,
y: 1600
}, {
x: 628,
y: 1600
}, {
x: 1420,
y: 1600
}, {
x: 1484,
y: 1600
}, {
x: 1548,
y: 1600
},
// Corner clusters
{
x: 200,
y: 300
}, {
x: 264,
y: 300
}, {
x: 200,
y: 364
}, {
x: 1784,
y: 300
}, {
x: 1848,
y: 300
}, {
x: 1784,
y: 364
}];
for (var i = 0; i < treeClusterPositions.length; i++) {
var tree = LK.getAsset('tree', {
anchorX: 0.5,
anchorY: 0.5,
width: 128,
height: 128
});
tree.x = treeClusterPositions[i].x;
tree.y = treeClusterPositions[i].y;
forestObjects.push(tree);
game.addChild(tree);
}
// Place bushes in organized pattern between trees and houses
var bushPositions = [
// Around left houses
{
x: 600,
y: 650
}, {
x: 600,
y: 750
}, {
x: 600,
y: 850
}, {
x: 600,
y: 950
}, {
x: 500,
y: 800
}, {
x: 500,
y: 1000
}, {
x: 500,
y: 1200
},
// Around right houses
{
x: 1450,
y: 650
}, {
x: 1450,
y: 750
}, {
x: 1450,
y: 850
}, {
x: 1450,
y: 950
}, {
x: 1550,
y: 800
}, {
x: 1550,
y: 1000
}, {
x: 1550,
y: 1200
},
// Along path edges
{
x: 900,
y: 600
}, {
x: 1150,
y: 600
}, {
x: 900,
y: 1000
}, {
x: 1150,
y: 1000
}, {
x: 900,
y: 1400
}, {
x: 1150,
y: 1400
},
// Scattered decorative bushes
{
x: 400,
y: 900
}, {
x: 1650,
y: 900
}, {
x: 400,
y: 1300
}, {
x: 1650,
y: 1300
}];
for (var i = 0; i < bushPositions.length; i++) {
var bush = LK.getAsset('bush', {
anchorX: 0.5,
anchorY: 0.5,
width: 64,
height: 64
});
bush.x = bushPositions[i].x;
bush.y = bushPositions[i].y;
forestObjects.push(bush);
game.addChild(bush);
}
isInMine = false;
}
function openMerchantInterface() {
// Simple merchant interaction - sell all items
var totalValue = 0;
var itemsSold = [];
for (var item in inventory) {
if (inventory[item] > 0) {
var itemValue = getItemValue(item);
var itemTotal = inventory[item] * itemValue;
totalValue += itemTotal;
itemsSold.push(item + ' x' + inventory[item] + ' = ' + itemTotal + ' coins');
inventory[item] = 0; // Clear inventory
}
}
if (totalValue > 0) {
LK.setScore(LK.getScore() + totalValue);
// Visual feedback
LK.effects.flashScreen(0x00FF00, 500);
}
}
function getItemValue(itemType) {
switch (itemType) {
case 'rock':
return 1;
case 'coal':
return 3;
case 'copper_ore':
return 5;
case 'iron_ore':
return 8;
case 'gold_ore':
return 15;
case 'gem':
return 25;
case 'slime':
return 2;
default:
return 1;
}
}
Heart pixart. In-Game asset. 2d. High contrast. No shadows
Muro de piedras tipo cueva. In-Game asset. 2d. High contrast. No shadows
Slime pixart cute. In-Game asset. 2d. High contrast. No shadows
Minero pixart cute. In-Game asset. 2d. High contrast. No shadows
Escalera pixart. In-Game asset. 2d. High contrast. No shadows
Gold ore poxart. In-Game asset. 2d. High contrast. No shadows
Coal ore. In-Game asset. 2d. High contrast. No shadows
Chopper ore pixart. In-Game asset. 2d. High contrast. No shadows
Rocas pixart. In-Game asset. 2d. High contrast. No shadows
Iron ore pixart. In-Game asset. 2d. High contrast. No shadows
Gema de mina super especial pixart. In-Game asset. 2d. High contrast. No shadows
flechita hacia arriba pixart. In-Game asset. 2d. High contrast. No shadows
pico de madera pixart. In-Game asset. 2d. High contrast. No shadows
espada de madera pixart. In-Game asset. 2d. High contrast. No shadows
quitale el circulo del casco
que el minero este mirando de frente y llendo de frente
suelo de tierra pixart. In-Game asset. 2d. High contrast. No shadows
boton de un inventario pixelart. In-Game asset. 2d. High contrast. No shadows
quitar la palabra "inventory"
entrada a una mina pixelart. In-Game asset. 2d. High contrast. No shadows
lobo babeando pixelart. In-Game asset. 2d. High contrast. No shadows
arbusto pixelart. In-Game asset. 2d. High contrast. No shadows
cesped pixelart. In-Game asset. 2d. High contrast. No shadows
npc market pixelart. In-Game asset. 2d. High contrast. No shadows
coin pixelart. In-Game asset. 2d. High contrast. No shadows