User prompt
oyuncu köylüye saldırırsa köylü oyuncudan kaçar veya saldırır
User prompt
köylüler zıplayabilir
User prompt
köylüler blok koyabilir ve kırabilir
User prompt
köylüleri öldürebilelim ve yerçekiminden etkilensin
User prompt
make villager to inventory
User prompt
make villager egg
User prompt
yeni biomlar = lav havuzları köyler (köylülerde var) mağralar
User prompt
başlangıç menüsü ekle
User prompt
oyuna farklı farklı başarımlar ekle
User prompt
oyuncu lav ve suyun içinden geçsin ve lavdan geçince efekt gelsin ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
su ve lav birleşince bir tepkime olsun
User prompt
başarımlar yerinin boyunu 2ye böl
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var Achievement = Container.expand(function (achievementData) { var self = Container.call(this); // Background var bgGraphics = self.attachAsset('menuBg', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.6, scaleY: 0.3, alpha: 0.9 }); // Title text var titleText = new Text2('Achievement Unlocked!', { size: 36, fill: 0xFFD700 }); titleText.anchor.set(0.5, 0.5); titleText.x = 0; titleText.y = -30; self.addChild(titleText); // Achievement name var nameText = new Text2(achievementData.name, { size: 28, fill: 0xFFFFFF }); nameText.anchor.set(0.5, 0.5); nameText.x = 0; nameText.y = 0; self.addChild(nameText); // Achievement description var descText = new Text2(achievementData.description, { size: 22, fill: 0xCCCCCC }); descText.anchor.set(0.5, 0.5); descText.x = 0; descText.y = 25; self.addChild(descText); self.show = function () { self.alpha = 0; self.scaleX = 0.5; self.scaleY = 0.5; self.visible = true; tween(self, { alpha: 1, scaleX: 1, scaleY: 1 }, { duration: 300, easing: tween.easeOut }); // Auto hide after 3 seconds LK.setTimeout(function () { tween(self, { alpha: 0, scaleX: 0.8, scaleY: 0.8 }, { duration: 200, onFinish: function onFinish() { self.visible = false; } }); }, 3000); }; // Initially hidden self.visible = false; return self; }); var AchievementMenu = Container.expand(function () { var self = Container.call(this); self.isVisible = false; // Background var bgGraphics = self.attachAsset('menuBg', { anchorX: 0.5, anchorY: 0.5, alpha: 0.9, scaleX: 1.2, scaleY: 3.0 }); // Title text var titleText = new Text2('Achievements', { size: 48, fill: 0xFFFFFF }); titleText.anchor.set(0.5, 0.5); titleText.x = 0; titleText.y = -300; self.addChild(titleText); // Close button var closeButton = self.attachAsset('closeButton', { anchorX: 0.5, anchorY: 0.5 }); closeButton.x = 350; closeButton.y = -300; // Achievement list container var achievementList = new Container(); self.addChild(achievementList); // Page navigation buttons var prevPageButton = self.attachAsset('menuButton', { anchorX: 0.5, anchorY: 0.5, alpha: 0.8, scaleX: 0.8, scaleY: 0.5 }); prevPageButton.x = -200; prevPageButton.y = 300; var prevPageText = new Text2('PREV', { size: 28, fill: 0xFFFFFF }); prevPageText.anchor.set(0.5, 0.5); prevPageText.x = -200; prevPageText.y = 300; self.addChild(prevPageText); var nextPageButton = self.attachAsset('menuButton', { anchorX: 0.5, anchorY: 0.5, alpha: 0.8, scaleX: 0.8, scaleY: 0.5 }); nextPageButton.x = 200; nextPageButton.y = 300; var nextPageText = new Text2('NEXT', { size: 28, fill: 0xFFFFFF }); nextPageText.anchor.set(0.5, 0.5); nextPageText.x = 200; nextPageText.y = 300; self.addChild(nextPageText); // Page indicator text var pageIndicatorText = new Text2('', { size: 24, fill: 0xCCCCCC }); pageIndicatorText.anchor.set(0.5, 0.5); pageIndicatorText.x = 0; pageIndicatorText.y = 300; self.addChild(pageIndicatorText); self.updateAchievements = function () { // Clear existing achievement displays while (achievementList.children.length > 0) { achievementList.removeChild(achievementList.children[0]); } // Get all achievement IDs as array for pagination var allAchievementIds = []; for (var achievementId in achievementDefinitions) { allAchievementIds.push(achievementId); } // Calculate pagination var totalPages = Math.ceil(allAchievementIds.length / achievementsPerPage); var startIndex = currentAchievementPage * achievementsPerPage; var endIndex = Math.min(startIndex + achievementsPerPage, allAchievementIds.length); // Update page indicator pageIndicatorText.setText('Page ' + (currentAchievementPage + 1) + ' of ' + totalPages); // Update button visibility prevPageButton.alpha = currentAchievementPage > 0 ? 0.8 : 0.3; prevPageText.fill = currentAchievementPage > 0 ? 0xFFFFFF : 0x666666; nextPageButton.alpha = currentAchievementPage < totalPages - 1 ? 0.8 : 0.3; nextPageText.fill = currentAchievementPage < totalPages - 1 ? 0xFFFFFF : 0x666666; var yOffset = -200; var achievementIndex = 0; // Display achievements for current page for (var i = startIndex; i < endIndex; i++) { var achievementId = allAchievementIds[i]; var achievement = achievementDefinitions[achievementId]; var isUnlocked = achievements[achievementId] || false; // Achievement container var achievementContainer = new Container(); achievementContainer.y = yOffset + achievementIndex * 80; // Achievement background var achievementBg = achievementContainer.attachAsset('menuButton', { anchorX: 0.5, anchorY: 0.5, alpha: isUnlocked ? 0.8 : 0.3, scaleX: 2.8, scaleY: 0.6 }); // Achievement name var nameText = new Text2(achievement.name, { size: 32, fill: isUnlocked ? 0xFFD700 : 0x888888 }); nameText.anchor.set(0.5, 0.5); nameText.x = 0; nameText.y = -15; achievementContainer.addChild(nameText); // Achievement description var descText = new Text2(achievement.description, { size: 24, fill: isUnlocked ? 0xFFFFFF : 0x666666 }); descText.anchor.set(0.5, 0.5); descText.x = 0; descText.y = 10; achievementContainer.addChild(descText); // Status text var statusText = new Text2(isUnlocked ? 'UNLOCKED' : 'LOCKED', { size: 20, fill: isUnlocked ? 0x00FF00 : 0xFF4444 }); statusText.anchor.set(1, 0.5); statusText.x = 150; statusText.y = 0; achievementContainer.addChild(statusText); achievementList.addChild(achievementContainer); achievementIndex++; } }; // Page navigation interactions prevPageButton.down = function (x, y, obj) { if (currentAchievementPage > 0) { prevPageButton.alpha = 1.0; currentAchievementPage--; self.updateAchievements(); } }; prevPageButton.up = function (x, y, obj) { prevPageButton.alpha = currentAchievementPage > 0 ? 0.8 : 0.3; }; nextPageButton.down = function (x, y, obj) { var totalPages = Math.ceil(Object.keys(achievementDefinitions).length / achievementsPerPage); if (currentAchievementPage < totalPages - 1) { nextPageButton.alpha = 1.0; currentAchievementPage++; self.updateAchievements(); } }; nextPageButton.up = function (x, y, obj) { var totalPages = Math.ceil(Object.keys(achievementDefinitions).length / achievementsPerPage); nextPageButton.alpha = currentAchievementPage < totalPages - 1 ? 0.8 : 0.3; }; // Close button interaction closeButton.down = function (x, y, obj) { closeButton.alpha = 0.7; self.hide(); }; closeButton.up = function (x, y, obj) { closeButton.alpha = 1.0; }; self.show = function () { self.isVisible = true; currentAchievementPage = 0; // Reset to first page when opening self.updateAchievements(); self.alpha = 0; self.visible = true; tween(self, { alpha: 1 }, { duration: 200 }); }; self.hide = function () { self.isVisible = false; tween(self, { alpha: 0 }, { duration: 200, onFinish: function onFinish() { self.visible = false; } }); }; // Initially hidden self.visible = false; return self; }); var Block = Container.expand(function (blockType) { var self = Container.call(this); self.blockType = blockType; self.gridX = 0; self.gridY = 0; var blockGraphics = self.attachAsset(blockType, { anchorX: 0.5, anchorY: 0.5 }); // Add a subtle border effect blockGraphics.alpha = 0.9; self.setGridPosition = function (gridX, gridY) { self.gridX = gridX; self.gridY = gridY; self.x = gridX * GRID_SIZE + GRID_SIZE / 2 + GRID_OFFSET_X; self.y = gridY * GRID_SIZE + GRID_SIZE / 2 + GRID_OFFSET_Y; }; return self; }); var BlockSelectionMenu = Container.expand(function () { var self = Container.call(this); self.isVisible = false; // Background var bgGraphics = self.attachAsset('menuBg', { anchorX: 0.5, anchorY: 0.5, alpha: 0.9, scaleY: 4.0 }); // Title text var titleText = new Text2('Select Block Type', { size: 48, fill: 0xFFFFFF }); titleText.anchor.set(0.5, 0.5); titleText.x = 0; titleText.y = -400; self.addChild(titleText); // Close button var closeButton = self.attachAsset('closeButton', { anchorX: 0.5, anchorY: 0.5 }); closeButton.x = 280; closeButton.y = -400; // Block selection buttons self.menuButtons = []; var allBlockTypes = Object.keys(inventory); var buttonsPerRow = 3; var buttonSpacing = 160; for (var i = 0; i < allBlockTypes.length; i++) { var button = new Container(); // Button background var buttonBg = button.attachAsset('menuButton', { anchorX: 0.5, anchorY: 0.5, alpha: 0.8 }); // Block preview var blockPreview = button.attachAsset(allBlockTypes[i], { anchorX: 0.5, anchorY: 0.5, scaleX: 0.9, scaleY: 0.9 }); // Block name text var nameText = new Text2(allBlockTypes[i], { size: 26, fill: 0xFFFFFF }); nameText.anchor.set(0.5, 0); nameText.x = 0; nameText.y = 45; button.addChild(nameText); // Inventory count text var countText = new Text2(inventory[allBlockTypes[i]].toString(), { size: 24, fill: 0xFFDD44 }); countText.anchor.set(0.5, 0); countText.x = 0; countText.y = 65; button.addChild(countText); // Position button var col = i % buttonsPerRow; var row = Math.floor(i / buttonsPerRow); button.x = (col - 1) * buttonSpacing; button.y = row * buttonSpacing - 30; // Store button data button.blockType = allBlockTypes[i]; button.bgGraphics = buttonBg; button.countText = countText; // Button interaction button.down = function (x, y, obj) { this.bgGraphics.alpha = 1.0; selectedBlockType = this.blockType; updateToolbarSelection(); self.hide(); }; button.up = function (x, y, obj) { this.bgGraphics.alpha = 0.8; }; self.menuButtons.push(button); self.addChild(button); } // Close button interaction closeButton.down = function (x, y, obj) { closeButton.alpha = 0.7; self.hide(); }; closeButton.up = function (x, y, obj) { closeButton.alpha = 1.0; }; self.show = function () { self.isVisible = true; self.alpha = 0; self.visible = true; tween(self, { alpha: 1 }, { duration: 200 }); }; self.hide = function () { self.isVisible = false; tween(self, { alpha: 0 }, { duration: 200, onFinish: function onFinish() { self.visible = false; } }); }; self.updateInventoryCounts = function () { for (var i = 0; i < self.menuButtons.length; i++) { var button = self.menuButtons[i]; if (button.countText && button.blockType) { button.countText.setText(inventory[button.blockType].toString()); } } }; // Initially hidden self.visible = false; return self; }); var Character = Container.expand(function () { var self = Container.call(this); var characterGraphics = self.attachAsset('character', { anchorX: 0.5, anchorY: 0.5 }); self.gridX = 0; self.gridY = 0; self.targetX = 0; self.targetY = 0; self.isMoving = false; self.setGridPosition = function (gridX, gridY) { self.gridX = gridX; self.gridY = gridY; self.targetX = gridX * GRID_SIZE + GRID_SIZE / 2 + GRID_OFFSET_X; self.targetY = gridY * GRID_SIZE + GRID_SIZE / 2 + GRID_OFFSET_Y; if (!self.isMoving) { self.x = self.targetX; self.y = self.targetY; } }; self.moveToGrid = function (gridX, gridY) { if (self.isMoving) return false; if (!isValidGridPosition(gridX, gridY)) return false; // Check if there's a block at the target position (only block movement if not flying) // Allow passing through water and lava blocks if (!isFlying && grid[gridX] && grid[gridX][gridY] !== null) { var targetBlock = grid[gridX][gridY]; if (targetBlock.blockType !== 'water' && targetBlock.blockType !== 'lava') { return false; } } self.isMoving = true; self.gridX = gridX; self.gridY = gridY; self.targetX = gridX * GRID_SIZE + GRID_SIZE / 2 + GRID_OFFSET_X; self.targetY = gridY * GRID_SIZE + GRID_SIZE / 2 + GRID_OFFSET_Y; // Reset gravity when manually moving (especially important in flying mode) if (isFlying) { characterGravity = 0; } // Adjust movement speed based on flying state var moveDuration = isFlying ? 100 : 200; tween(self, { x: self.targetX, y: self.targetY }, { duration: moveDuration, easing: isFlying ? tween.easeOut : tween.easeInOut, onFinish: function onFinish() { self.isMoving = false; // Track movement for achievements moveCount++; storage.moveCount = moveCount; // Track jumping (moving up) for boooing achievement if (gridY < self.gridY) { jumpCount++; storage.jumpCount = jumpCount; } // Track distance traveled var distance = Math.abs(gridX - self.gridX) + Math.abs(gridY - self.gridY); totalDistanceTraveled += distance; storage.totalDistanceTraveled = totalDistanceTraveled; // Track corner visits if ((gridX === 0 || gridX === GRID_WIDTH - 1) && (gridY === 0 || gridY === GRID_HEIGHT - 1)) { var corner = gridX + '_' + gridY; visitedCorners[corner] = true; storage.visitedCorners = visitedCorners; } // Track top/bottom row visits if (gridY === 0) { topRowVisits++; storage.topRowVisits = topRowVisits; } if (gridY === GRID_HEIGHT - 1) { bottomRowVisits++; storage.bottomRowVisits = bottomRowVisits; } checkAllAchievements(); } }); return true; }; self.update = function () { // Reset gravity when flying - do this first if (isFlying) { characterGravity = 0; } else { // Apply gravity if character is not moving, not supported, and not flying if (!self.isMoving) { var hasSupport = false; // Check if character has support below (block or ground) var belowY = self.gridY + 1; if (belowY >= GRID_HEIGHT) { // At bottom of world, has support hasSupport = true; } else if (grid[self.gridX] && grid[self.gridX][belowY] !== null) { // Block below, has support hasSupport = true; } if (!hasSupport) { // Character should fall characterGravity += characterGravityAcceleration; if (characterGravity > characterMaxFallSpeed) { characterGravity = characterMaxFallSpeed; } // Find where character should fall to var fallToY = self.gridY; for (var checkY = self.gridY + 1; checkY < GRID_HEIGHT; checkY++) { if (grid[self.gridX][checkY] !== null) { break; } fallToY = checkY; } // Move character down if there's a place to fall if (fallToY > self.gridY) { var targetY = Math.min(fallToY, self.gridY + Math.floor(characterGravity)); if (targetY !== self.gridY) { self.moveToGrid(self.gridX, targetY); } } } else { // Character has support, reset gravity characterGravity = 0; } } } // Check if character is touching a portal if (!self.isMoving) { for (var i = 0; i < placedBlocks.length; i++) { var block = placedBlocks[i]; if (block.blockType === 'portal' && block.gridX === self.gridX && block.gridY === self.gridY) { block.teleportCharacter(); break; } } } // Check if character is passing through lava and add effect if (grid[self.gridX] && grid[self.gridX][self.gridY] !== null) { var currentBlock = grid[self.gridX][self.gridY]; if (currentBlock.blockType === 'lava') { // Flash character red with tween effect tween(characterGraphics, { tint: 0xff0000 }, { duration: 200, easing: tween.easeOut }); tween(characterGraphics, { tint: 0xffffff }, { duration: 200, easing: tween.easeOut }); // Add screen flash effect LK.effects.flashScreen(0xff4500, 300); // Track lava touches for survivalist achievement lavaTouches++; storage.lavaTouches = lavaTouches; checkAllAchievements(); } } // Track time spent at world center for centerist achievement var centerX = Math.floor(GRID_WIDTH / 2); var centerY = Math.floor(GRID_HEIGHT / 2); if (Math.abs(self.gridX - centerX) <= 2 && Math.abs(self.gridY - centerY) <= 2) { centerTime++; } // Character is always on top if (self.parent) { var parent = self.parent; parent.removeChild(self); parent.addChild(self); } }; return self; }); var ControlButton = Container.expand(function (direction) { var self = Container.call(this); self.direction = direction; var bgGraphics = self.attachAsset('controlBg', { anchorX: 0.5, anchorY: 0.5, alpha: 0.7 }); var arrowGraphics = self.attachAsset('arrow' + direction.charAt(0).toUpperCase() + direction.slice(1), { anchorX: 0.5, anchorY: 0.5, scaleX: 0.7, scaleY: 0.7 }); self.down = function (x, y, obj) { bgGraphics.alpha = 1.0; var newX = character.gridX; var newY = character.gridY; if (direction === 'up') newY--;else if (direction === 'down') newY++;else if (direction === 'left') newX--;else if (direction === 'right') newX++; character.moveToGrid(newX, newY); }; self.up = function (x, y, obj) { bgGraphics.alpha = 0.7; }; return self; }); var GridCell = Container.expand(function () { var self = Container.call(this); var cellGraphics = self.attachAsset('gridCell', { anchorX: 0.5, anchorY: 0.5, alpha: 0.1 }); self.gridX = 0; self.gridY = 0; self.isEmpty = true; self.setGridPosition = function (gridX, gridY) { self.gridX = gridX; self.gridY = gridY; self.x = gridX * GRID_SIZE + GRID_SIZE / 2 + GRID_OFFSET_X; self.y = gridY * GRID_SIZE + GRID_SIZE / 2 + GRID_OFFSET_Y; }; self.highlight = function () { cellGraphics.alpha = 0.3; }; self.unhighlight = function () { cellGraphics.alpha = 0.1; }; return self; }); var Lava = Container.expand(function () { var self = Container.call(this); self.blockType = 'lava'; self.gridX = 0; self.gridY = 0; self.isFlowing = false; self.flowCooldown = 0; self.damageTimer = 0; var lavaGraphics = self.attachAsset('lava', { anchorX: 0.5, anchorY: 0.5 }); // Add glowing effect lavaGraphics.alpha = 0.9; self.setGridPosition = function (gridX, gridY) { self.gridX = gridX; self.gridY = gridY; self.x = gridX * GRID_SIZE + GRID_SIZE / 2 + GRID_OFFSET_X; self.y = gridY * GRID_SIZE + GRID_SIZE / 2 + GRID_OFFSET_Y; }; self.update = function () { // Pulsing glow effect lavaGraphics.alpha = 0.8 + Math.sin(LK.ticks * 0.15) * 0.15; lavaGraphics.tint = 0xff4500 + Math.floor(Math.sin(LK.ticks * 0.1) * 20) * 0x010000; // Handle damage to character if (character && character.gridX === self.gridX && character.gridY === self.gridY && !character.isMoving) { self.damageTimer++; if (self.damageTimer >= 60) { // 1 second of contact // Flash character red and teleport away from lava LK.effects.flashObject(character, 0xff0000, 500); LK.effects.flashScreen(0xff0000, 300); // Move character to nearest safe position self.teleportCharacterToSafety(); self.damageTimer = 0; } } else { self.damageTimer = 0; } // Lava flowing mechanics disabled - no spreading // if (self.flowCooldown > 0) { // self.flowCooldown--; // } else { // self.tryToFlow(); // self.flowCooldown = 120; // Flow every 2 seconds // } }; self.teleportCharacterToSafety = function () { // Find nearest safe position var safePositions = []; for (var radius = 1; radius <= 5; radius++) { for (var dx = -radius; dx <= radius; dx++) { for (var dy = -radius; dy <= radius; dy++) { var checkX = self.gridX + dx; var checkY = self.gridY + dy; if (isValidGridPosition(checkX, checkY) && grid[checkX][checkY] === null) { // Check if position has ground support below var hasSupport = false; if (checkY + 1 >= GRID_HEIGHT) { hasSupport = true; } else if (grid[checkX][checkY + 1] !== null && grid[checkX][checkY + 1].blockType !== 'lava') { hasSupport = true; } if (hasSupport) { safePositions.push({ x: checkX, y: checkY }); } } } } if (safePositions.length > 0) break; } if (safePositions.length > 0) { var safePos = safePositions[0]; // Take closest safe position character.setGridPosition(safePos.x, safePos.y); } }; self.tryToFlow = function () { // Lava flows down first, then horizontally var flowDirections = [{ x: 0, y: 1 }, // Down { x: -1, y: 0 }, // Left { x: 1, y: 0 }, // Right { x: -1, y: 1 }, // Down-left { x: 1, y: 1 } // Down-right ]; for (var i = 0; i < flowDirections.length; i++) { var dir = flowDirections[i]; var targetX = self.gridX + dir.x; var targetY = self.gridY + dir.y; if (isValidGridPosition(targetX, targetY) && grid[targetX][targetY] === null) { // Only flow if there are less than 3 lava blocks already var nearbyLavaCount = 0; for (var checkX = targetX - 1; checkX <= targetX + 1; checkX++) { for (var checkY = targetY - 1; checkY <= targetY + 1; checkY++) { if (isValidGridPosition(checkX, checkY) && grid[checkX][checkY] !== null && grid[checkX][checkY].blockType === 'lava') { nearbyLavaCount++; } } } if (nearbyLavaCount < 3) { // Create new lava block var newLava = new Lava(); newLava.setGridPosition(targetX, targetY); game.addChild(newLava); grid[targetX][targetY] = newLava; placedBlocks.push(newLava); LK.effects.flashObject(newLava, 0xffff00, 300); break; } } } }; return self; }); var Portal = Container.expand(function () { var self = Container.call(this); self.blockType = 'portal'; self.gridX = 0; self.gridY = 0; self.isActive = true; self.cooldownTime = 0; var portalGraphics = self.attachAsset('portal', { anchorX: 0.5, anchorY: 0.5 }); // Add glowing effect portalGraphics.alpha = 0.8; self.setGridPosition = function (gridX, gridY) { self.gridX = gridX; self.gridY = gridY; self.x = gridX * GRID_SIZE + GRID_SIZE / 2 + GRID_OFFSET_X; self.y = gridY * GRID_SIZE + GRID_SIZE / 2 + GRID_OFFSET_Y; }; self.teleportCharacter = function () { if (!self.isActive || self.cooldownTime > 0) return false; if (!character || character.isMoving) return false; // Find all other active portals var otherPortals = []; for (var i = 0; i < placedBlocks.length; i++) { var block = placedBlocks[i]; if (block !== self && block.blockType === 'portal' && block.isActive && block.cooldownTime <= 0) { otherPortals.push(block); } } if (otherPortals.length === 0) { // No other portals available - teleport to heaven! // Create heaven effect with golden background and clouds game.setBackgroundColor(0xFFD700); // Golden sky // Flash screen with heavenly light LK.effects.flashScreen(0xFFFFFF, 2000); // Teleport character to top of world center var heavenX = Math.floor(GRID_WIDTH / 2); var heavenY = 0; // Top of the world character.setGridPosition(heavenX, heavenY); // Add visual effects LK.effects.flashObject(self, 0xFFD700, 1000); LK.effects.flashObject(character, 0xFFFFFF, 1000); // Play portal sound LK.getSound('portal').play(); // Set cooldown self.cooldownTime = 300; // 5 seconds cooldown // Track portal usage and heaven visits portalUses++; heavenVisits++; storage.portalUses = portalUses; storage.heavenVisits = heavenVisits; checkAllAchievements(); // Reset background after effect LK.setTimeout(function () { game.setBackgroundColor(0x87CEEB); // Back to sky blue }, 3000); return true; } // Choose random portal to teleport to var targetPortal = otherPortals[Math.floor(Math.random() * otherPortals.length)]; // Teleport character character.setGridPosition(targetPortal.gridX, targetPortal.gridY); // Add visual effects LK.effects.flashObject(self, 0x9400d3, 500); LK.effects.flashObject(targetPortal, 0x9400d3, 500); LK.effects.flashObject(character, 0x00ffff, 300); // Play portal sound LK.getSound('portal').play(); // Set cooldown for both portals self.cooldownTime = 180; // 3 seconds at 60fps targetPortal.cooldownTime = 180; // Track portal usage portalUses++; storage.portalUses = portalUses; checkAllAchievements(); return true; }; self.update = function () { // Handle cooldown if (self.cooldownTime > 0) { self.cooldownTime--; portalGraphics.alpha = 0.3 + self.cooldownTime / 180 * 0.5; } else { portalGraphics.alpha = 0.8 + Math.sin(LK.ticks * 0.1) * 0.2; // Pulsing effect } // Check if character is on portal if (character && character.gridX === self.gridX && character.gridY === self.gridY && !character.isMoving) { self.teleportCharacter(); } }; return self; }); var Sand = Container.expand(function () { var self = Container.call(this); self.blockType = 'sand'; self.gridX = 0; self.gridY = 0; self.isFalling = false; self.fallSpeed = 0; self.maxFallSpeed = 8; self.fallAcceleration = 0.8; var sandGraphics = self.attachAsset('sand', { anchorX: 0.5, anchorY: 0.5 }); self.setGridPosition = function (gridX, gridY) { self.gridX = gridX; self.gridY = gridY; self.x = gridX * GRID_SIZE + GRID_SIZE / 2 + GRID_OFFSET_X; self.y = gridY * GRID_SIZE + GRID_SIZE / 2 + GRID_OFFSET_Y; }; self.update = function () { // Check if sand should fall if (!self.isFalling) { var hasSupport = false; var belowY = self.gridY + 1; // Check if at bottom or has block below if (belowY >= GRID_HEIGHT) { hasSupport = true; } else if (grid[self.gridX] && grid[self.gridX][belowY] !== null) { hasSupport = true; } // Start falling if no support if (!hasSupport) { self.isFalling = true; self.fallSpeed = 0; } } // Handle falling physics if (self.isFalling) { self.fallSpeed += self.fallAcceleration; if (self.fallSpeed > self.maxFallSpeed) { self.fallSpeed = self.maxFallSpeed; } // Calculate new grid position var newGridY = self.gridY + Math.floor(self.fallSpeed / 4); // Check if we can fall to new position if (newGridY < GRID_HEIGHT && (grid[self.gridX][newGridY] === null || grid[self.gridX][newGridY] === self)) { // Update grid if (grid[self.gridX][self.gridY] === self) { grid[self.gridX][self.gridY] = null; } self.gridY = newGridY; grid[self.gridX][self.gridY] = self; self.setGridPosition(self.gridX, self.gridY); } else { // Stop falling - hit something or reached bottom self.isFalling = false; self.fallSpeed = 0; } } }; return self; }); var ToolbarButton = Container.expand(function (blockType) { var self = Container.call(this); self.blockType = blockType; self.isSelected = false; var bgGraphics = self.attachAsset('toolbarBg', { anchorX: 0.5, anchorY: 0.5, alpha: 0.8 }); var blockGraphics = self.attachAsset(blockType, { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.8 }); var selectedBorder = self.attachAsset('selectedBorder', { anchorX: 0.5, anchorY: 0.5, alpha: 0 }); self.setSelected = function (selected) { self.isSelected = selected; selectedBorder.alpha = selected ? 0.8 : 0; bgGraphics.alpha = selected ? 1.0 : 0.8; }; self.down = function (x, y, obj) { selectedBlockType = self.blockType; updateToolbarSelection(); }; return self; }); var Villager = Container.expand(function () { var self = Container.call(this); self.gridX = 0; self.gridY = 0; self.moveTimer = 0; self.moveDirection = 1; self.isAlive = true; self.gravity = 0; self.maxFallSpeed = 8; self.gravityAcceleration = 0.5; self.isFalling = false; var villagerGraphics = self.attachAsset('character', { anchorX: 0.5, anchorY: 0.5 }); villagerGraphics.tint = 0x8B4513; // Brown color for villagers villagerGraphics.scaleX = 0.8; villagerGraphics.scaleY = 0.8; self.setGridPosition = function (gridX, gridY) { self.gridX = gridX; self.gridY = gridY; self.x = gridX * GRID_SIZE + GRID_SIZE / 2 + GRID_OFFSET_X; self.y = gridY * GRID_SIZE + GRID_SIZE / 2 + GRID_OFFSET_Y; }; self.kill = function () { if (!self.isAlive) return; self.isAlive = false; // Create death effects LK.effects.flashObject(self, 0xff0000, 500); // Create particle effects for death for (var p = 0; p < 6; p++) { var particle = new Container(); var particleGraphics = particle.attachAsset('character', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.2, scaleY: 0.2 }); particleGraphics.tint = 0x8B4513; particle.x = self.x; particle.y = self.y; game.addChild(particle); // Random direction for each particle var angle = p / 6 * Math.PI * 2; var speed = 60 + Math.random() * 40; var targetX = particle.x + Math.cos(angle) * speed; var targetY = particle.y + Math.sin(angle) * speed; // Animate particle flying out and fading tween(particle, { x: targetX, y: targetY, scaleX: 0.05, scaleY: 0.05, alpha: 0, rotation: Math.random() * Math.PI * 2 }, { duration: 400 + Math.random() * 200, easing: tween.easeOut, onFinish: function onFinish() { particle.destroy(); } }); } // Remove from villagers array for (var i = villagers.length - 1; i >= 0; i--) { if (villagers[i] === self) { villagers.splice(i, 1); break; } } // Destroy villager after effects LK.setTimeout(function () { self.destroy(); }, 500); }; self.update = function () { if (!self.isAlive) return; // Apply gravity to villager var hasSupport = false; if (self.gridY + 1 >= GRID_HEIGHT) { hasSupport = true; } else if (grid[self.gridX] && grid[self.gridX][self.gridY + 1] !== null) { hasSupport = true; } if (!hasSupport) { // Villager should fall self.gravity += self.gravityAcceleration; if (self.gravity > self.maxFallSpeed) { self.gravity = self.maxFallSpeed; } // Find where villager should fall to var fallToY = self.gridY; for (var checkY = self.gridY + 1; checkY < GRID_HEIGHT; checkY++) { if (grid[self.gridX][checkY] !== null) { break; } fallToY = checkY; } // Move villager down if there's a place to fall if (fallToY > self.gridY) { var targetY = Math.min(fallToY, self.gridY + Math.floor(self.gravity)); if (targetY !== self.gridY) { self.setGridPosition(self.gridX, targetY); } } } else { // Villager has support, reset gravity self.gravity = 0; } self.moveTimer++; // Simple AI movement every 3 seconds if (self.moveTimer >= 180) { self.moveTimer = 0; // Try to move in current direction var newX = self.gridX + self.moveDirection; // Check bounds and obstacles if (newX < 0 || newX >= GRID_WIDTH || grid[newX] && grid[newX][self.gridY] !== null) { self.moveDirection *= -1; // Reverse direction } else { // Move to new position if valid var hasSupport = false; if (self.gridY + 1 >= GRID_HEIGHT) { hasSupport = true; } else if (grid[newX] && grid[newX][self.gridY + 1] !== null) { hasSupport = true; } if (hasSupport) { self.setGridPosition(newX, self.gridY); } } } // Keep villager on top of other objects if (self.parent) { var parent = self.parent; parent.removeChild(self); parent.addChild(self); } }; return self; }); var VillagerEgg = Container.expand(function () { var self = Container.call(this); self.blockType = 'villagerEgg'; self.gridX = 0; self.gridY = 0; self.hatchTimer = 0; self.hatchTime = 1800; // 30 seconds at 60fps var eggGraphics = self.attachAsset('villagerEgg', { anchorX: 0.5, anchorY: 0.5 }); // Add glowing effect eggGraphics.alpha = 0.9; self.setGridPosition = function (gridX, gridY) { self.gridX = gridX; self.gridY = gridY; self.x = gridX * GRID_SIZE + GRID_SIZE / 2 + GRID_OFFSET_X; self.y = gridY * GRID_SIZE + GRID_SIZE / 2 + GRID_OFFSET_Y; }; self.update = function () { // Gentle pulsing effect eggGraphics.alpha = 0.8 + Math.sin(LK.ticks * 0.1) * 0.1; eggGraphics.scaleX = 1.0 + Math.sin(LK.ticks * 0.08) * 0.05; eggGraphics.scaleY = 1.0 + Math.sin(LK.ticks * 0.08) * 0.05; // Increment hatch timer self.hatchTimer++; // Change color as it gets closer to hatching var hatchProgress = self.hatchTimer / self.hatchTime; if (hatchProgress > 0.7) { eggGraphics.tint = 0xFFE4B5; // Warmer color when close to hatching } else if (hatchProgress > 0.5) { eggGraphics.tint = 0xF5DEB3; // Slightly warmer } // Hatch when timer reaches hatch time if (self.hatchTimer >= self.hatchTime) { self.hatchVillager(); } }; self.hatchVillager = function () { // Create hatching effects LK.effects.flashObject(self, 0xFFFFFF, 500); LK.effects.flashScreen(0xFFD700, 200); // Create a new villager at the egg position var newVillager = new Villager(); newVillager.setGridPosition(self.gridX, self.gridY); game.addChild(newVillager); villagers.push(newVillager); // Remove egg from grid and placedBlocks grid[self.gridX][self.gridY] = null; for (var i = placedBlocks.length - 1; i >= 0; i--) { if (placedBlocks[i] === self) { placedBlocks.splice(i, 1); break; } } // Play hatching sound LK.getSound('place').play(); // Create particle effects for hatching for (var p = 0; p < 8; p++) { var particle = new Container(); var particleGraphics = particle.attachAsset('villagerEgg', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.2, scaleY: 0.2 }); particle.x = self.x; particle.y = self.y; game.addChild(particle); // Random direction for each particle var angle = p / 8 * Math.PI * 2; var speed = 60 + Math.random() * 40; var targetX = particle.x + Math.cos(angle) * speed; var targetY = particle.y + Math.sin(angle) * speed; // Animate particle flying out and fading tween(particle, { x: targetX, y: targetY, scaleX: 0.05, scaleY: 0.05, alpha: 0, rotation: Math.random() * Math.PI * 2 }, { duration: 400 + Math.random() * 200, easing: tween.easeOut, onFinish: function onFinish() { particle.destroy(); } }); } // Destroy the egg self.destroy(); }; return self; }); var Water = Container.expand(function () { var self = Container.call(this); self.blockType = 'water'; self.gridX = 0; self.gridY = 0; self.isFlowing = false; self.flowCooldown = 0; var waterGraphics = self.attachAsset('water', { anchorX: 0.5, anchorY: 0.5 }); // Add water effects waterGraphics.alpha = 0.7; // Semi-transparent water self.setGridPosition = function (gridX, gridY) { self.gridX = gridX; self.gridY = gridY; self.x = gridX * GRID_SIZE + GRID_SIZE / 2 + GRID_OFFSET_X; self.y = gridY * GRID_SIZE + GRID_SIZE / 2 + GRID_OFFSET_Y; }; self.update = function () { // Gentle wave effect waterGraphics.alpha = 0.6 + Math.sin(LK.ticks * 0.08) * 0.1; waterGraphics.tint = 0x4169e1 + Math.floor(Math.sin(LK.ticks * 0.05) * 10) * 0x000100; // Check for lava collision in adjacent positions var checkPositions = [{ x: self.gridX - 1, y: self.gridY }, // Left { x: self.gridX + 1, y: self.gridY }, // Right { x: self.gridX, y: self.gridY - 1 }, // Up { x: self.gridX, y: self.gridY + 1 }, // Down { x: self.gridX - 1, y: self.gridY - 1 }, // Up-left { x: self.gridX + 1, y: self.gridY - 1 }, // Up-right { x: self.gridX - 1, y: self.gridY + 1 }, // Down-left { x: self.gridX + 1, y: self.gridY + 1 } // Down-right ]; for (var i = 0; i < checkPositions.length; i++) { var pos = checkPositions[i]; if (isValidGridPosition(pos.x, pos.y) && grid[pos.x][pos.y] !== null) { var adjacentBlock = grid[pos.x][pos.y]; if (adjacentBlock.blockType === 'lava') { // Water and lava reaction - create steam explosion effect LK.effects.flashScreen(0xFFFFFF, 800); LK.effects.flashObject(self, 0xFFFFFF, 600); LK.effects.flashObject(adjacentBlock, 0xFFFFFF, 600); // Create stone block at water position var stoneBlock = new Block('stone'); stoneBlock.setGridPosition(self.gridX, self.gridY); game.addChild(stoneBlock); grid[self.gridX][self.gridY] = stoneBlock; placedBlocks.push(stoneBlock); // Remove water block self.destroy(); for (var j = placedBlocks.length - 1; j >= 0; j--) { if (placedBlocks[j] === self) { placedBlocks.splice(j, 1); break; } } // Remove lava block adjacentBlock.destroy(); grid[pos.x][pos.y] = null; for (var k = placedBlocks.length - 1; k >= 0; k--) { if (placedBlocks[k] === adjacentBlock) { placedBlocks.splice(k, 1); break; } } // Create stone block at lava position too var stoneBlock2 = new Block('stone'); stoneBlock2.setGridPosition(pos.x, pos.y); game.addChild(stoneBlock2); grid[pos.x][pos.y] = stoneBlock2; placedBlocks.push(stoneBlock2); // Play reaction sound LK.getSound('break').play(); // Track water-lava reactions waterLavaReactions++; storage.waterLavaReactions = waterLavaReactions; checkAllAchievements(); return; // Exit after reaction } } } // Water flowing mechanics disabled - no spreading // if (self.flowCooldown > 0) { // self.flowCooldown--; // } else { // self.tryToFlow(); // self.flowCooldown = 90; // Flow every 1.5 seconds // } }; self.tryToFlow = function () { // Water flows down first, then horizontally var flowDirections = [{ x: 0, y: 1 }, // Down { x: -1, y: 0 }, // Left { x: 1, y: 0 }, // Right { x: -1, y: 1 }, // Down-left { x: 1, y: 1 } // Down-right ]; for (var i = 0; i < flowDirections.length; i++) { var dir = flowDirections[i]; var targetX = self.gridX + dir.x; var targetY = self.gridY + dir.y; if (isValidGridPosition(targetX, targetY) && grid[targetX][targetY] === null) { // Only flow if there are less than 4 water blocks nearby var nearbyWaterCount = 0; for (var checkX = targetX - 1; checkX <= targetX + 1; checkX++) { for (var checkY = targetY - 1; checkY <= targetY + 1; checkY++) { if (isValidGridPosition(checkX, checkY) && grid[checkX][checkY] !== null && grid[checkX][checkY].blockType === 'water') { nearbyWaterCount++; } } } if (nearbyWaterCount < 4) { // Create new water block var newWater = new Water(); newWater.setGridPosition(targetX, targetY); game.addChild(newWater); grid[targetX][targetY] = newWater; placedBlocks.push(newWater); LK.effects.flashObject(newWater, 0x87ceeb, 300); break; } } } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x87CEEB }); /**** * Game Code ****/ var GRID_SIZE = 80; var GRID_WIDTH = 20; var GRID_HEIGHT = 20; var GRID_OFFSET_X = (2048 - GRID_WIDTH * GRID_SIZE) / 2; var GRID_OFFSET_Y = 200; var selectedBlockType = 'dirt'; var blockTypes = ['dirt', 'stone', 'wood', 'grass', 'grassDark', 'grassLight', 'sand', 'diamond', 'gold', 'portal', 'lava', 'water', 'villagerEgg', 'villager']; var inventory = { dirt: 50, stone: 30, wood: 25, grass: 20, grassDark: 15, grassLight: 15, sand: 25, diamond: 5, gold: 8, portal: 3, lava: 10, water: 15, villagerEgg: 3, villager: 5 }; // Achievement system var achievements = storage.achievements || {}; var currentAchievementPage = 0; var achievementsPerPage = 8; var achievementDefinitions = { firstBlock: { name: "First Builder", description: "Place your first block", unlocked: false }, destroyer: { name: "Destroyer", description: "Break 10 blocks", unlocked: false }, architect: { name: "Architect", description: "Place 50 blocks", unlocked: false }, miner: { name: "Miner", description: "Break 50 blocks", unlocked: false }, collector: { name: "Collector", description: "Collect all block types", unlocked: false }, explorer: { name: "Explorer", description: "Move 100 times", unlocked: false }, masterBuilder: { name: "Master Builder", description: "Place 200 blocks", unlocked: false }, demolitionExpert: { name: "Demolition Expert", description: "Break 200 blocks", unlocked: false }, goldRush: { name: "Gold Rush", description: "Collect 20 gold blocks", unlocked: false }, diamondCollector: { name: "Diamond Collector", description: "Collect 15 diamond blocks", unlocked: false }, woodsman: { name: "Woodsman", description: "Collect 100 wood blocks", unlocked: false }, stoneAge: { name: "Stone Age", description: "Collect 150 stone blocks", unlocked: false }, adventurer: { name: "Adventurer", description: "Move 500 times", unlocked: false }, nomad: { name: "Nomad", description: "Move 1000 times", unlocked: false }, flightTime: { name: "Taking Flight", description: "Use flying mode 10 times", unlocked: false }, skyExplorer: { name: "Sky Explorer", description: "Spend 60 seconds in flying mode", unlocked: false }, areCrazy: { name: "are you crazy?", description: "Break each block type 10 times", unlocked: false }, boooing: { name: "boooing", description: "Jump 100 times", unlocked: false }, lavaLord: { name: "Lava Lord", description: "Place 25 lava blocks", unlocked: false }, waterMaster: { name: "Water Master", description: "Place 30 water blocks", unlocked: false }, speedBuilder: { name: "Speed Builder", description: "Place 20 blocks in 30 seconds", unlocked: false }, speedDestroyer: { name: "Speed Destroyer", description: "Break 15 blocks in 20 seconds", unlocked: false }, portalMaster: { name: "Portal Master", description: "Use portals 25 times", unlocked: false }, heavenReacher: { name: "Heaven Reacher", description: "Reach heaven biome 5 times", unlocked: false }, sandCastleKing: { name: "Sand Castle King", description: "Place 40 sand blocks", unlocked: false }, grassGardener: { name: "Grass Gardener", description: "Place 100 grass blocks total", unlocked: false }, undergroundExplorer: { name: "Underground Explorer", description: "Place blocks below Y level 15", unlocked: false }, skyBuilder: { name: "Sky Builder", description: "Place blocks above Y level 5", unlocked: false }, elementalReactor: { name: "Elemental Reactor", description: "Trigger 10 water-lava reactions", unlocked: false }, survivalist: { name: "Survivalist", description: "Survive 5 lava touches", unlocked: false }, teleporter: { name: "Teleporter", description: "Travel 1000 grid units total", unlocked: false }, perfectionist: { name: "Perfectionist", description: "Maintain max inventory for 5 minutes", unlocked: false }, nightOwl: { name: "Night Owl", description: "Play for 10 minutes straight", unlocked: false }, marathonPlayer: { name: "Marathon Player", description: "Play for 30 minutes straight", unlocked: false }, blockChain: { name: "Block Chain", description: "Place 10 blocks in a row without breaking", unlocked: false }, demolitionChain: { name: "Demolition Chain", description: "Break 10 blocks in a row without placing", unlocked: false }, rainbowBuilder: { name: "Rainbow Builder", description: "Place all 12 block types in one session", unlocked: false }, cornerExplorer: { name: "Corner Explorer", description: "Visit all 4 corners of the world", unlocked: false }, centerist: { name: "Centerist", description: "Spend 2 minutes at world center", unlocked: false }, pacifist: { name: "Pacifist", description: "Place 100 blocks without breaking any", unlocked: false }, destroyer2: { name: "World Destroyer", description: "Break 100 blocks without placing any", unlocked: false }, inventoryManager: { name: "Inventory Manager", description: "Use every block type at least once", unlocked: false }, highFlyer: { name: "High Flyer", description: "Fly to the top row 10 times", unlocked: false }, deepDigger: { name: "Deep Digger", description: "Reach the bottom row 10 times", unlocked: false } }; // Achievement counters var blocksPlaced = storage.blocksPlaced || 0; var blocksBroken = storage.blocksBroken || 0; var moveCount = storage.moveCount || 0; var goldCollected = storage.goldCollected || 0; var diamondCollected = storage.diamondCollected || 0; var woodCollected = storage.woodCollected || 0; var stoneCollected = storage.stoneCollected || 0; var flyingActivations = storage.flyingActivations || 0; var flyingStartTime = 0; var totalFlyingTime = storage.totalFlyingTime || 0; var blockTypeBrokenCount = storage.blockTypeBrokenCount || {}; var jumpCount = storage.jumpCount || 0; var lavaPlaced = storage.lavaPlaced || 0; var waterPlaced = storage.waterPlaced || 0; var portalUses = storage.portalUses || 0; var heavenVisits = storage.heavenVisits || 0; var sandPlaced = storage.sandPlaced || 0; var grassPlaced = storage.grassPlaced || 0; var waterLavaReactions = storage.waterLavaReactions || 0; var lavaTouches = storage.lavaTouches || 0; var totalDistanceTraveled = storage.totalDistanceTraveled || 0; var gameStartTime = LK.ticks; var maxInventoryStartTime = 0; var totalMaxInventoryTime = storage.totalMaxInventoryTime || 0; var consecutiveBlocksPlaced = 0; var consecutiveBlocksBroken = 0; var usedBlockTypesThisSession = {}; var visitedCorners = storage.visitedCorners || {}; var centerTime = 0; var consecutivePlacingStreak = storage.consecutivePlacingStreak || 0; var consecutiveBreakingStreak = storage.consecutiveBreakingStreak || 0; var topRowVisits = storage.topRowVisits || 0; var bottomRowVisits = storage.bottomRowVisits || 0; var undergroundBuilding = storage.undergroundBuilding || 0; var skyBuilding = storage.skyBuilding || 0; var buildingSpeedStart = 0; var buildingSpeedCount = 0; var breakingSpeedStart = 0; var breakingSpeedCount = 0; var grid = []; var placedBlocks = []; var villagers = []; var toolbarButtons = []; var controlButtons = []; var pressTimer = null; var isLongPress = false; var pressStartTime = 0; var character = null; var blockSelectionMenu = null; var menuButton = null; var achievementNotification = null; var achievementMenu = null; var characterGravity = 0; // Current falling speed var characterMaxFallSpeed = 8; // Maximum falling speed var characterGravityAcceleration = 0.5; // How fast gravity accelerates var isFlying = false; // Flying mode toggle var flyingSpeed = 4; // Speed when flying var flyingVerticalSpeed = 3; // Vertical movement speed when flying function checkAchievement(achievementId) { if (achievements[achievementId]) return; var achieved = false; switch (achievementId) { case 'firstBlock': achieved = blocksPlaced >= 1; break; case 'destroyer': achieved = blocksBroken >= 10; break; case 'architect': achieved = blocksPlaced >= 50; break; case 'miner': achieved = blocksBroken >= 50; break; case 'collector': // Check if player has collected all block types var hasAllTypes = true; for (var blockType in inventory) { if (inventory[blockType] <= 0) { hasAllTypes = false; break; } } achieved = hasAllTypes; break; case 'explorer': achieved = moveCount >= 100; break; case 'masterBuilder': achieved = blocksPlaced >= 200; break; case 'demolitionExpert': achieved = blocksBroken >= 200; break; case 'goldRush': achieved = goldCollected >= 20; break; case 'diamondCollector': achieved = diamondCollected >= 15; break; case 'woodsman': achieved = woodCollected >= 100; break; case 'stoneAge': achieved = stoneCollected >= 150; break; case 'adventurer': achieved = moveCount >= 500; break; case 'nomad': achieved = moveCount >= 1000; break; case 'flightTime': achieved = flyingActivations >= 10; break; case 'skyExplorer': achieved = totalFlyingTime >= 60000; // 60 seconds in milliseconds break; case 'areCrazy': // Check if each block type has been broken at least 10 times achieved = true; for (var i = 0; i < blockTypes.length; i++) { var blockType = blockTypes[i]; var brokenCount = blockTypeBrokenCount[blockType] || 0; if (brokenCount < 10) { achieved = false; break; } } break; case 'boooing': achieved = jumpCount >= 100; break; case 'lavaLord': achieved = lavaPlaced >= 25; break; case 'waterMaster': achieved = waterPlaced >= 30; break; case 'speedBuilder': achieved = buildingSpeedCount >= 20; break; case 'speedDestroyer': achieved = breakingSpeedCount >= 15; break; case 'portalMaster': achieved = portalUses >= 25; break; case 'heavenReacher': achieved = heavenVisits >= 5; break; case 'sandCastleKing': achieved = sandPlaced >= 40; break; case 'grassGardener': achieved = grassPlaced >= 100; break; case 'undergroundExplorer': achieved = undergroundBuilding >= 1; break; case 'skyBuilder': achieved = skyBuilding >= 1; break; case 'elementalReactor': achieved = waterLavaReactions >= 10; break; case 'survivalist': achieved = lavaTouches >= 5; break; case 'teleporter': achieved = totalDistanceTraveled >= 1000; break; case 'perfectionist': achieved = totalMaxInventoryTime >= 300000; // 5 minutes in milliseconds break; case 'nightOwl': var currentTime = LK.ticks; achieved = currentTime - gameStartTime >= 36000; // 10 minutes at 60fps break; case 'marathonPlayer': var currentTime = LK.ticks; achieved = currentTime - gameStartTime >= 108000; // 30 minutes at 60fps break; case 'blockChain': achieved = consecutivePlacingStreak >= 10; break; case 'demolitionChain': achieved = consecutiveBreakingStreak >= 10; break; case 'rainbowBuilder': achieved = Object.keys(usedBlockTypesThisSession).length >= 12; break; case 'cornerExplorer': achieved = Object.keys(visitedCorners).length >= 4; break; case 'centerist': achieved = centerTime >= 7200; // 2 minutes at 60fps break; case 'pacifist': achieved = consecutivePlacingStreak >= 100; break; case 'destroyer2': achieved = consecutiveBreakingStreak >= 100; break; case 'inventoryManager': var usedAllTypes = true; for (var i = 0; i < blockTypes.length; i++) { if (!usedBlockTypesThisSession[blockTypes[i]]) { usedAllTypes = false; break; } } achieved = usedAllTypes; break; case 'highFlyer': achieved = topRowVisits >= 10; break; case 'deepDigger': achieved = bottomRowVisits >= 10; break; } if (achieved) { unlockAchievement(achievementId); } } function unlockAchievement(achievementId) { if (achievements[achievementId]) return; achievements[achievementId] = true; storage.achievements = achievements; // Update the achievement menu to show the newly unlocked achievement if (achievementMenu) { achievementMenu.updateAchievements(); // Show the achievement menu temporarily if not already visible if (!achievementMenu.isVisible) { achievementMenu.show(); // Auto-hide after a few seconds LK.setTimeout(function () { if (achievementMenu && achievementMenu.isVisible) { achievementMenu.hide(); } }, 3000); } } } function checkAllAchievements() { for (var achievementId in achievementDefinitions) { checkAchievement(achievementId); } } // Initialize grid for (var x = 0; x < GRID_WIDTH; x++) { grid[x] = []; for (var y = 0; y < GRID_HEIGHT; y++) { grid[x][y] = null; var gridCell = new GridCell(); gridCell.setGridPosition(x, y); game.addChild(gridCell); } } // Initialize character at top of world character = new Character(); var randomX = Math.floor(Math.random() * GRID_WIDTH); var topY = 0; // Always start at the very top character.setGridPosition(randomX, topY); game.addChild(character); // Create block selection menu blockSelectionMenu = new BlockSelectionMenu(); blockSelectionMenu.x = 1024; blockSelectionMenu.y = 800; LK.gui.addChild(blockSelectionMenu); // Create achievement menu at top layer achievementMenu = new AchievementMenu(); achievementMenu.x = 1024; achievementMenu.y = 400; LK.gui.addChild(achievementMenu); // Create menu button menuButton = new Container(); var menuBg = menuButton.attachAsset('toolbarBg', { anchorX: 0.5, anchorY: 0.5, alpha: 0.8 }); var menuText = new Text2('MENU', { size: 36, fill: 0xFFFFFF }); menuText.anchor.set(0.5, 0.5); menuText.x = 0; menuText.y = 0; menuButton.addChild(menuText); menuButton.x = 2048 - 80; menuButton.y = 150; menuButton.down = function (x, y, obj) { menuBg.alpha = 1.0; if (!blockSelectionMenu.isVisible) { blockSelectionMenu.show(); } }; menuButton.up = function (x, y, obj) { menuBg.alpha = 0.8; }; game.addChild(menuButton); // Create achievements button at the top var achievementsButton = new Container(); var achievementsBg = achievementsButton.attachAsset('toolbarBg', { anchorX: 0.5, anchorY: 0.5, alpha: 0.8 }); var achievementsText = new Text2('ACHIEVEMENTS', { size: 28, fill: 0xFFFFFF }); achievementsText.anchor.set(0.5, 0.5); achievementsText.x = 0; achievementsText.y = 0; achievementsButton.addChild(achievementsText); achievementsButton.x = 1024; achievementsButton.y = 50; achievementsButton.down = function (x, y, obj) { achievementsBg.alpha = 1.0; if (!achievementMenu.isVisible) { achievementMenu.show(); } }; achievementsButton.up = function (x, y, obj) { achievementsBg.alpha = 0.8; }; game.addChild(achievementsButton); // Create flying toggle button var flyingButton = new Container(); var flyingBg = flyingButton.attachAsset('toolbarBg', { anchorX: 0.5, anchorY: 0.5, alpha: 0.8 }); var flyingText = new Text2('FLY', { size: 32, fill: 0xFFFFFF }); flyingText.anchor.set(0.5, 0.5); flyingText.x = 0; flyingText.y = 0; flyingButton.addChild(flyingText); flyingButton.x = 2048 - 80; flyingButton.y = 350; flyingButton.down = function (x, y, obj) { flyingBg.alpha = 1.0; // Toggle flying mode var wasFlying = isFlying; isFlying = !isFlying; // Track flying time and activations if (isFlying && !wasFlying) { // Started flying flyingActivations++; storage.flyingActivations = flyingActivations; flyingStartTime = LK.ticks; checkAllAchievements(); } else if (!isFlying && wasFlying) { // Stopped flying if (flyingStartTime > 0) { var flyingDuration = (LK.ticks - flyingStartTime) * (1000 / 60); // Convert ticks to milliseconds totalFlyingTime += flyingDuration; storage.totalFlyingTime = totalFlyingTime; flyingStartTime = 0; checkAllAchievements(); } } // Update button appearance - recreate the background with new color flyingButton.removeChild(flyingBg); flyingBg = flyingButton.attachAsset('toolbarBg', { anchorX: 0.5, anchorY: 0.5, alpha: 1.0 }); if (isFlying) { flyingBg.tint = 0x00FF00; } else { flyingBg.tint = 0xFFFFFF; } flyingText.setText(isFlying ? 'LAND' : 'FLY'); // Visual feedback if (isFlying) { LK.effects.flashObject(character, 0x00FFFF, 500); } }; flyingButton.up = function (x, y, obj) { flyingBg.alpha = 0.8; }; game.addChild(flyingButton); // Create flying status display var flyingStatusText = new Text2('', { size: 28, fill: 0x00FFFF }); flyingStatusText.anchor.set(0.5, 0); flyingStatusText.x = 1024; flyingStatusText.y = 100; LK.gui.addChild(flyingStatusText); // Create toolbar var toolbarY = 2732 - 120; var toolbarStartX = (2048 - blockTypes.length * 120) / 2; for (var i = 0; i < blockTypes.length; i++) { var button = new ToolbarButton(blockTypes[i]); button.x = toolbarStartX + i * 120 + 60; button.y = toolbarY; toolbarButtons.push(button); LK.gui.addChild(button); } // Create inventory display var inventoryTexts = {}; for (var i = 0; i < blockTypes.length; i++) { var blockType = blockTypes[i]; var inventoryText = new Text2(inventory[blockType].toString(), { size: 36, fill: 0xFFFFFF }); inventoryText.anchor.set(0.5, 0); inventoryText.x = toolbarStartX + i * 120 + 60; inventoryText.y = toolbarY + 60; inventoryTexts[blockType] = inventoryText; LK.gui.addChild(inventoryText); } // Create control buttons var controlButtonSize = 100; var controlPadding = 20; var controlCenterX = 150; var controlCenterY = GRID_OFFSET_Y + GRID_HEIGHT * GRID_SIZE + 150; var directions = [{ dir: 'up', x: 0, y: -1 }, { dir: 'down', x: 0, y: 1 }, { dir: 'left', x: -1, y: 0 }, { dir: 'right', x: 1, y: 0 }]; for (var i = 0; i < directions.length; i++) { var dirInfo = directions[i]; var button = new ControlButton(dirInfo.dir); button.x = controlCenterX + dirInfo.x * (controlButtonSize + controlPadding); button.y = controlCenterY + dirInfo.y * (controlButtonSize + controlPadding); controlButtons.push(button); game.addChild(button); } function updateToolbarSelection() { for (var i = 0; i < toolbarButtons.length; i++) { toolbarButtons[i].setSelected(toolbarButtons[i].blockType === selectedBlockType); } } function updateInventoryDisplay() { for (var blockType in inventoryTexts) { inventoryTexts[blockType].setText(inventory[blockType].toString()); } // Update block selection menu inventory counts if (blockSelectionMenu) { blockSelectionMenu.updateInventoryCounts(); } } function getGridPosition(worldX, worldY) { var gridX = Math.floor((worldX - GRID_OFFSET_X) / GRID_SIZE); var gridY = Math.floor((worldY - GRID_OFFSET_Y) / GRID_SIZE); return { x: gridX, y: gridY }; } function isValidGridPosition(gridX, gridY) { return gridX >= 0 && gridX < GRID_WIDTH && gridY >= 0 && gridY < GRID_HEIGHT; } function placeBlock(gridX, gridY) { if (!isValidGridPosition(gridX, gridY)) return false; if (grid[gridX][gridY] !== null) return false; if (inventory[selectedBlockType] <= 0) return false; // Don't place block on character position if (character && gridX === character.gridX && gridY === character.gridY) return false; var block; if (selectedBlockType === 'sand') { block = new Sand(); } else if (selectedBlockType === 'portal') { block = new Portal(); } else if (selectedBlockType === 'lava') { block = new Lava(); } else if (selectedBlockType === 'water') { block = new Water(); } else if (selectedBlockType === 'villagerEgg') { block = new VillagerEgg(); } else if (selectedBlockType === 'villager') { // Create a villager directly instead of a block var newVillager = new Villager(); newVillager.setGridPosition(gridX, gridY); game.addChild(newVillager); villagers.push(newVillager); inventory[selectedBlockType]--; updateInventoryDisplay(); LK.getSound('place').play(); // Track achievement progress blocksPlaced++; storage.blocksPlaced = blocksPlaced; consecutivePlacingStreak++; storage.consecutivePlacingStreak = consecutivePlacingStreak; consecutiveBreakingStreak = 0; // Reset breaking streak storage.consecutiveBreakingStreak = 0; // Track used block types this session usedBlockTypesThisSession[selectedBlockType] = true; checkAllAchievements(); return true; } else { block = new Block(selectedBlockType); } block.setGridPosition(gridX, gridY); game.addChild(block); grid[gridX][gridY] = block; placedBlocks.push(block); inventory[selectedBlockType]--; updateInventoryDisplay(); LK.getSound('place').play(); // Track achievement progress blocksPlaced++; storage.blocksPlaced = blocksPlaced; consecutivePlacingStreak++; storage.consecutivePlacingStreak = consecutivePlacingStreak; consecutiveBreakingStreak = 0; // Reset breaking streak storage.consecutiveBreakingStreak = 0; // Track used block types this session usedBlockTypesThisSession[selectedBlockType] = true; // Track specific block type placements if (selectedBlockType === 'lava') { lavaPlaced++; storage.lavaPlaced = lavaPlaced; } if (selectedBlockType === 'water') { waterPlaced++; storage.waterPlaced = waterPlaced; } if (selectedBlockType === 'sand') { sandPlaced++; storage.sandPlaced = sandPlaced; } if (selectedBlockType === 'grass' || selectedBlockType === 'grassDark' || selectedBlockType === 'grassLight') { grassPlaced++; storage.grassPlaced = grassPlaced; } // Track building location achievements if (gridY >= 15) { undergroundBuilding++; storage.undergroundBuilding = undergroundBuilding; } if (gridY <= 5) { skyBuilding++; storage.skyBuilding = skyBuilding; } // Track speed building if (buildingSpeedStart === 0) { buildingSpeedStart = LK.ticks; buildingSpeedCount = 1; } else { var timeDiff = LK.ticks - buildingSpeedStart; if (timeDiff <= 1800) { // 30 seconds at 60fps buildingSpeedCount++; } else { buildingSpeedStart = LK.ticks; buildingSpeedCount = 1; } } checkAllAchievements(); return true; } function removeBlock(gridX, gridY) { if (!isValidGridPosition(gridX, gridY)) return false; if (grid[gridX][gridY] === null) return false; var block = grid[gridX][gridY]; var blockType = block.blockType; // If breaking a portal, teleport character to heaven biome if (blockType === 'portal') { // Transition to heaven biome permanently game.setBackgroundColor(0xFFD700); // Golden heaven sky // Flash screen with heavenly light LK.effects.flashScreen(0xFFFFFF, 2000); // Teleport character to top of world center var heavenX = Math.floor(GRID_WIDTH / 2); var heavenY = 0; // Top of the world character.setGridPosition(heavenX, heavenY); // Add visual effects LK.effects.flashObject(block, 0xFFD700, 1000); LK.effects.flashObject(character, 0xFFFFFF, 1000); // Play portal sound LK.getSound('portal').play(); // Clear all existing blocks to create clean heaven environment for (var x = 0; x < GRID_WIDTH; x++) { for (var y = 0; y < GRID_HEIGHT; y++) { if (grid[x][y] !== null && grid[x][y] !== block) { var existingBlock = grid[x][y]; existingBlock.destroy(); grid[x][y] = null; // Remove from placedBlocks array for (var j = placedBlocks.length - 1; j >= 0; j--) { if (placedBlocks[j] === existingBlock) { placedBlocks.splice(j, 1); break; } } } } } // Generate heaven environment with golden blocks and clouds selectedBlockType = 'gold'; // Create golden platform in heaven var heavenPlatformY = Math.floor(GRID_HEIGHT * 0.8); for (var x = 0; x < GRID_WIDTH; x++) { placeBlock(x, heavenPlatformY); if (Math.random() < 0.3) { placeBlock(x, heavenPlatformY - 1); // Add some elevation } } // Add diamond clouds scattered around selectedBlockType = 'diamond'; for (var i = 0; i < 15; i++) { var cloudX = Math.floor(Math.random() * GRID_WIDTH); var cloudY = Math.floor(Math.random() * heavenPlatformY * 0.7); if (isValidGridPosition(cloudX, cloudY) && grid[cloudX][cloudY] === null) { placeBlock(cloudX, cloudY); } } // Reset selection selectedBlockType = 'dirt'; updateToolbarSelection(); } // Create particle effects - multiple small pieces flying out for (var p = 0; p < 6; p++) { var particle = new Container(); var particleGraphics = particle.attachAsset(blockType, { anchorX: 0.5, anchorY: 0.5, scaleX: 0.3, scaleY: 0.3 }); particle.x = block.x; particle.y = block.y; game.addChild(particle); // Random direction for each particle var angle = p / 6 * Math.PI * 2 + (Math.random() - 0.5) * 0.5; var speed = 100 + Math.random() * 80; var targetX = particle.x + Math.cos(angle) * speed; var targetY = particle.y + Math.sin(angle) * speed; // Animate particle flying out and fading tween(particle, { x: targetX, y: targetY, scaleX: 0.1, scaleY: 0.1, alpha: 0, rotation: Math.random() * Math.PI * 2 }, { duration: 300 + Math.random() * 200, easing: tween.easeOut, onFinish: function onFinish() { particle.destroy(); } }); } // Add breaking animation with flash effect and rotation LK.effects.flashObject(block, 0xFFFFFF, 200); // Add screen shake effect for impact var originalX = game.x; var originalY = game.y; var shakeIntensity = 8; tween(game, { x: originalX + shakeIntensity }, { duration: 30, easing: tween.easeOut }); LK.setTimeout(function () { tween(game, { x: originalX - shakeIntensity }, { duration: 30, easing: tween.easeOut }); }, 30); LK.setTimeout(function () { tween(game, { x: originalX, y: originalY }, { duration: 40, easing: tween.easeOut }); }, 60); // Remove from placedBlocks array for (var i = placedBlocks.length - 1; i >= 0; i--) { if (placedBlocks[i] === block) { placedBlocks.splice(i, 1); break; } } // Animate block destruction with scaling and rotation tween(block, { scaleX: 0, scaleY: 0, alpha: 0, rotation: Math.PI * 0.5 }, { duration: 150, easing: tween.easeIn, onFinish: function onFinish() { block.destroy(); } }); grid[gridX][gridY] = null; inventory[blockType]++; updateInventoryDisplay(); LK.getSound('break').play(); // Track achievement progress blocksBroken++; storage.blocksBroken = blocksBroken; consecutiveBreakingStreak++; storage.consecutiveBreakingStreak = consecutiveBreakingStreak; consecutivePlacingStreak = 0; // Reset placing streak storage.consecutivePlacingStreak = 0; // Track specific resource collection if (blockType === 'gold') { goldCollected++; storage.goldCollected = goldCollected; } else if (blockType === 'diamond') { diamondCollected++; storage.diamondCollected = diamondCollected; } else if (blockType === 'wood') { woodCollected++; storage.woodCollected = woodCollected; } else if (blockType === 'stone') { stoneCollected++; storage.stoneCollected = stoneCollected; } // Track block type breaking for 'are you crazy?' achievement if (!blockTypeBrokenCount[blockType]) { blockTypeBrokenCount[blockType] = 0; } blockTypeBrokenCount[blockType]++; storage.blockTypeBrokenCount = blockTypeBrokenCount; // Track speed breaking if (breakingSpeedStart === 0) { breakingSpeedStart = LK.ticks; breakingSpeedCount = 1; } else { var timeDiff = LK.ticks - breakingSpeedStart; if (timeDiff <= 1200) { // 20 seconds at 60fps breakingSpeedCount++; } else { breakingSpeedStart = LK.ticks; breakingSpeedCount = 1; } } checkAllAchievements(); return true; } // Initialize toolbar selection updateToolbarSelection(); updateInventoryDisplay(); game.down = function (x, y, obj) { var gridPos = getGridPosition(x, y); pressStartTime = LK.ticks; isLongPress = false; // Check if clicking on a villager first for (var i = 0; i < villagers.length; i++) { var villager = villagers[i]; if (villager.isAlive && villager.gridX === gridPos.x && villager.gridY === gridPos.y) { villager.kill(); return; // Exit early if we killed a villager } } // Start long press timer for breaking blocks if (pressTimer) { LK.clearTimeout(pressTimer); } pressTimer = LK.setTimeout(function () { isLongPress = true; // Break only the specific block at clicked position if (isValidGridPosition(gridPos.x, gridPos.y) && grid[gridPos.x][gridPos.y] !== null) { removeBlock(gridPos.x, gridPos.y); } }, 500); // 500ms long press }; game.up = function (x, y, obj) { // Clear the long press timer if (pressTimer) { LK.clearTimeout(pressTimer); pressTimer = null; } // If it wasn't a long press, place a block if (!isLongPress) { var gridPos = getGridPosition(x, y); if (isValidGridPosition(gridPos.x, gridPos.y)) { placeBlock(gridPos.x, gridPos.y); } } }; // Generate procedural world with biomes function generateWorld() { // Reset selected block type to dirt for generation selectedBlockType = 'dirt'; updateToolbarSelection(); // Create height map for smooth terrain var heightMap = []; var baseHeightLevel = Math.floor(GRID_HEIGHT * 0.7); // Base terrain level for (var x = 0; x < GRID_WIDTH; x++) { // Generate smooth terrain using sine waves var primary = Math.sin(x / GRID_WIDTH * Math.PI * 2) * 3; var secondary = Math.sin(x / GRID_WIDTH * Math.PI * 6) * 1.5; var noise = (Math.random() - 0.5) * 2; var height = baseHeightLevel + primary + secondary + noise; heightMap[x] = Math.floor(Math.max(5, Math.min(height, GRID_HEIGHT - 3))); } // Smooth the height map to reduce abrupt changes for (var pass = 0; pass < 2; pass++) { for (var x = 1; x < GRID_WIDTH - 1; x++) { var avg = (heightMap[x - 1] + heightMap[x] + heightMap[x + 1]) / 3; heightMap[x] = Math.floor(avg); } } // Define biome regions - now with 5 sections for more biomes var biome1 = Math.floor(GRID_WIDTH * 0.2); var biome2 = Math.floor(GRID_WIDTH * 0.4); var biome3 = Math.floor(GRID_WIDTH * 0.6); var biome4 = Math.floor(GRID_WIDTH * 0.8); var biomes = ['plains', 'forest', 'mountains', 'lava_pools', 'village']; var currentBiomes = [biomes[Math.floor(Math.random() * biomes.length)], biomes[Math.floor(Math.random() * biomes.length)], biomes[Math.floor(Math.random() * biomes.length)], biomes[Math.floor(Math.random() * biomes.length)], biomes[Math.floor(Math.random() * biomes.length)]]; // Generate terrain layers for (var x = 0; x < GRID_WIDTH; x++) { var currentBiome; if (x < biome1) { currentBiome = currentBiomes[0]; } else if (x < biome2) { currentBiome = currentBiomes[1]; } else if (x < biome3) { currentBiome = currentBiomes[2]; } else if (x < biome4) { currentBiome = currentBiomes[3]; } else { currentBiome = currentBiomes[4]; } var baseHeight = heightMap[x]; var surfaceBlock = 'grass'; var treeChance = 0.15; var stoneChance = 0.1; // Biome-specific properties if (currentBiome === 'plains') { surfaceBlock = 'grass'; treeChance = 0.08; stoneChance = 0.05; } else if (currentBiome === 'forest') { surfaceBlock = 'grass'; treeChance = 0.25; // More trees stoneChance = 0.08; } else if (currentBiome === 'mountains') { surfaceBlock = 'stone'; // Rocky surface treeChance = 0.05; // Few trees at high altitude stoneChance = 0.25; // Very rocky // Adjust height for mountains baseHeight = Math.max(baseHeight - 3, Math.floor(GRID_HEIGHT * 0.5)); } else if (currentBiome === 'lava_pools') { surfaceBlock = 'stone'; // Rocky volcanic surface treeChance = 0.02; // Almost no trees stoneChance = 0.4; // Very rocky volcanic terrain // Slightly lower terrain for lava pools baseHeight = Math.max(baseHeight + 1, Math.floor(GRID_HEIGHT * 0.75)); } else if (currentBiome === 'village') { surfaceBlock = 'grass'; // Nice grassy village surface treeChance = 0.1; // Moderate trees stoneChance = 0.03; // Clean village area // Flatten terrain for village baseHeight = Math.floor(GRID_HEIGHT * 0.7); } // Place surface layer selectedBlockType = surfaceBlock; placeBlock(x, baseHeight); // Place sub-surface layers consistently selectedBlockType = 'dirt'; var dirtLayers = currentBiome === 'mountains' ? 2 : 3; for (var y = baseHeight + 1; y < Math.min(baseHeight + dirtLayers + 1, GRID_HEIGHT); y++) { placeBlock(x, y); } // Place stone in deeper layers consistently selectedBlockType = 'stone'; for (var y = baseHeight + dirtLayers + 1; y < GRID_HEIGHT; y++) { var stoneProb = currentBiome === 'mountains' ? 0.9 : 0.8; if (Math.random() < stoneProb) { placeBlock(x, y); } } // Add trees in groups for natural look if (Math.random() < treeChance && baseHeight > 2) { selectedBlockType = 'wood'; var treeHeight; if (currentBiome === 'forest') { treeHeight = Math.floor(Math.random() * 3) + 3; // Tall trees } else { treeHeight = Math.floor(Math.random() * 2) + 2; // Normal trees } for (var i = 0; i < treeHeight; i++) { var treeY = baseHeight - i - 1; if (treeY >= 0) { placeBlock(x, treeY); } } // Add tree leaves/branches if (currentBiome === 'forest' && treeHeight >= 3) { selectedBlockType = 'grassLight'; if (x > 0 && baseHeight - treeHeight >= 0) { placeBlock(x - 1, baseHeight - treeHeight + 1); } if (x < GRID_WIDTH - 1 && baseHeight - treeHeight >= 0) { placeBlock(x + 1, baseHeight - treeHeight + 1); } } } // Add surface features sparingly if (Math.random() < stoneChance && baseHeight > 0) { selectedBlockType = 'stone'; placeBlock(x, baseHeight - 1); } // Add biome-specific features occasionally if (currentBiome === 'mountains' && Math.random() < 0.1) { selectedBlockType = 'stone'; if (baseHeight > 1) { placeBlock(x, baseHeight - 1); } } else if (currentBiome === 'lava_pools' && Math.random() < 0.15) { // Create lava pools selectedBlockType = 'lava'; placeBlock(x, baseHeight + 1); if (Math.random() < 0.6) { placeBlock(x, baseHeight + 2); // Deeper lava } } else if (currentBiome === 'village' && Math.random() < 0.08) { // Create simple village structures selectedBlockType = 'wood'; for (var houseHeight = 0; houseHeight < 3; houseHeight++) { var houseY = baseHeight - houseHeight - 1; if (houseY >= 0) { placeBlock(x, houseY); } } } } // Add minimal scattered resources in logical places for (var i = 0; i < 15; i++) { var randX = Math.floor(Math.random() * GRID_WIDTH); var surfaceY = heightMap[randX]; // Place resources near surface or in underground areas var randY = Math.random() < 0.6 ? surfaceY + Math.floor(Math.random() * 3) + 1 : Math.floor(Math.random() * (GRID_HEIGHT - surfaceY - 5)) + surfaceY + 3; if (isValidGridPosition(randX, randY) && grid[randX][randY] === null) { var resourceType; if (randY > surfaceY + 2) { // Underground resources resourceType = Math.random() < 0.6 ? 'stone' : 'dirt'; } else { // Surface resources resourceType = blockTypes[Math.floor(Math.random() * blockTypes.length)]; } selectedBlockType = resourceType; placeBlock(randX, randY); } } // Add rare precious blocks deep underground for (var i = 0; i < 3; i++) { var randX = Math.floor(Math.random() * GRID_WIDTH); var surfaceY = heightMap[randX]; // Place deep underground only var randY = Math.floor(Math.random() * 3) + GRID_HEIGHT - 5; if (isValidGridPosition(randX, randY) && grid[randX][randY] === null) { var preciousType = Math.random() < 0.4 ? 'diamond' : 'gold'; selectedBlockType = preciousType; placeBlock(randX, randY); } } // Add portals with 10% chance - place 1-2 portals randomly if (Math.random() < 0.1) { var numPortals = Math.floor(Math.random() * 2) + 1; // 1 or 2 portals for (var p = 0; p < numPortals; p++) { var attempts = 0; var portalPlaced = false; while (attempts < 20 && !portalPlaced) { var randX = Math.floor(Math.random() * GRID_WIDTH); var surfaceY = heightMap[randX]; var randY = surfaceY - Math.floor(Math.random() * 3) - 1; // Place above surface if (isValidGridPosition(randX, randY) && grid[randX][randY] === null) { selectedBlockType = 'portal'; if (placeBlock(randX, randY)) { portalPlaced = true; } } attempts++; } } } // Create a few small, deliberate caves for (var caveCount = 0; caveCount < 2; caveCount++) { var caveX = Math.floor(Math.random() * (GRID_WIDTH - 4)) + 2; var surfaceHeight = heightMap[caveX]; var caveY = surfaceHeight + Math.floor(Math.random() * 4) + 3; var caveSize = 1; // Create small hollow areas for (var cx = caveX - caveSize; cx <= caveX + caveSize; cx++) { for (var cy = caveY - caveSize; cy <= caveY + caveSize; cy++) { if (isValidGridPosition(cx, cy) && grid[cx][cy] !== null) { var block = grid[cx][cy]; if (block) { block.destroy(); grid[cx][cy] = null; // Remove from placedBlocks array for (var j = placedBlocks.length - 1; j >= 0; j--) { if (placedBlocks[j] === block) { placedBlocks.splice(j, 1); break; } } } } } } } // Spawn villagers in village biomes for (var x = 0; x < GRID_WIDTH; x++) { var currentBiome; if (x < biome1) { currentBiome = currentBiomes[0]; } else if (x < biome2) { currentBiome = currentBiomes[1]; } else if (x < biome3) { currentBiome = currentBiomes[2]; } else if (x < biome4) { currentBiome = currentBiomes[3]; } else { currentBiome = currentBiomes[4]; } if (currentBiome === 'village' && Math.random() < 0.05) { // Find surface level for villager placement var surfaceY = heightMap[x]; var villagerY = surfaceY - 1; // Make sure villager has ground to stand on if (villagerY >= 0 && villagerY < GRID_HEIGHT) { var villager = new Villager(); villager.setGridPosition(x, villagerY); game.addChild(villager); villagers.push(villager); } } else if (currentBiome === 'village' && Math.random() < 0.03) { // Sometimes place villager eggs instead of villagers var surfaceY = heightMap[x]; var eggY = surfaceY - 1; if (eggY >= 0 && eggY < GRID_HEIGHT && grid[x][eggY] === null) { selectedBlockType = 'villagerEgg'; placeBlock(x, eggY); } } } // Create enhanced cave systems for (var caveCount = 0; caveCount < 4; caveCount++) { var caveX = Math.floor(Math.random() * (GRID_WIDTH - 6)) + 3; var surfaceHeight = heightMap[caveX]; var caveY = surfaceHeight + Math.floor(Math.random() * 6) + 4; var caveSize = Math.floor(Math.random() * 2) + 1; // 1-2 size caves // Create larger cave chambers for (var cx = caveX - caveSize; cx <= caveX + caveSize; cx++) { for (var cy = caveY - caveSize; cy <= caveY + caveSize; cy++) { if (isValidGridPosition(cx, cy) && grid[cx][cy] !== null) { var block = grid[cx][cy]; if (block) { block.destroy(); grid[cx][cy] = null; // Remove from placedBlocks array for (var j = placedBlocks.length - 1; j >= 0; j--) { if (placedBlocks[j] === block) { placedBlocks.splice(j, 1); break; } } } } } } // Add cave decorations - stalactites and stalagmites if (caveSize > 1) { selectedBlockType = 'stone'; // Stalactites from ceiling for (var i = 0; i < 3; i++) { var stalX = caveX + Math.floor(Math.random() * 3) - 1; var stalY = caveY - caveSize; if (isValidGridPosition(stalX, stalY) && grid[stalX][stalY] === null) { placeBlock(stalX, stalY); } } // Stalagmites from floor for (var i = 0; i < 2; i++) { var stalagX = caveX + Math.floor(Math.random() * 3) - 1; var stalagY = caveY + caveSize; if (isValidGridPosition(stalagX, stalagY) && grid[stalagX][stalagY] === null) { placeBlock(stalagX, stalagY); } } } } // Reset to dirt selection selectedBlockType = 'dirt'; updateToolbarSelection(); } // Generate the world after a short delay LK.setTimeout(function () { generateWorld(); }, 500); function applyGravity() { var blocksToMove = []; // Check all blocks from bottom to top for (var y = GRID_HEIGHT - 2; y >= 0; y--) { for (var x = 0; x < GRID_WIDTH; x++) { var block = grid[x][y]; if (block !== null) { // Check if block has support below var hasSupport = false; for (var checkY = y + 1; checkY < GRID_HEIGHT; checkY++) { if (grid[x][checkY] !== null) { hasSupport = true; break; } } // If no support, mark for falling if (!hasSupport) { var fallY = y; // Find where it should fall to for (var targetY = y + 1; targetY < GRID_HEIGHT; targetY++) { if (grid[x][targetY] !== null) { break; } fallY = targetY; } if (fallY !== y) { blocksToMove.push({ block: block, fromX: x, fromY: y, toX: x, toY: fallY }); } } } } } // Move blocks that need to fall for (var i = 0; i < blocksToMove.length; i++) { var moveData = blocksToMove[i]; var block = moveData.block; // Clear old position grid[moveData.fromX][moveData.fromY] = null; // Set new position grid[moveData.toX][moveData.toY] = block; block.setGridPosition(moveData.toX, moveData.toY); } } game.update = function () { // Apply gravity every few ticks to make blocks fall if (LK.ticks % 10 === 0) { applyGravity(); } // Update flying status display if (isFlying) { flyingStatusText.setText('FLYING MODE'); flyingStatusText.visible = true; // Track flying time for achievements if (flyingStartTime > 0) { var currentFlyingTime = (LK.ticks - flyingStartTime) * (1000 / 60); if (currentFlyingTime >= 1000) { // Check every second totalFlyingTime += 1000; storage.totalFlyingTime = totalFlyingTime; flyingStartTime = LK.ticks; checkAllAchievements(); } } } else { flyingStatusText.visible = false; } // Check if inventory is at maximum for perfectionist achievement var isMaxInventory = true; for (var blockType in inventory) { if (inventory[blockType] < 50) { isMaxInventory = false; break; } } if (isMaxInventory) { if (maxInventoryStartTime === 0) { maxInventoryStartTime = LK.ticks; } else { var maxInventoryDuration = (LK.ticks - maxInventoryStartTime) * (1000 / 60); totalMaxInventoryTime += 1000 / 60; // Add one frame worth of time storage.totalMaxInventoryTime = totalMaxInventoryTime; } } else { maxInventoryStartTime = 0; } // Update villagers for (var i = 0; i < villagers.length; i++) { villagers[i].update(); } // Replenish inventory slowly over time if (LK.ticks % 600 === 0) { // Every 10 seconds for (var blockType in inventory) { if (inventory[blockType] < 50) { inventory[blockType]++; } } updateInventoryDisplay(); checkAllAchievements(); } };
===================================================================
--- original.js
+++ change.js
@@ -976,8 +976,13 @@
self.gridX = 0;
self.gridY = 0;
self.moveTimer = 0;
self.moveDirection = 1;
+ self.isAlive = true;
+ self.gravity = 0;
+ self.maxFallSpeed = 8;
+ self.gravityAcceleration = 0.5;
+ self.isFalling = false;
var villagerGraphics = self.attachAsset('character', {
anchorX: 0.5,
anchorY: 0.5
});
@@ -989,9 +994,93 @@
self.gridY = gridY;
self.x = gridX * GRID_SIZE + GRID_SIZE / 2 + GRID_OFFSET_X;
self.y = gridY * GRID_SIZE + GRID_SIZE / 2 + GRID_OFFSET_Y;
};
+ self.kill = function () {
+ if (!self.isAlive) return;
+ self.isAlive = false;
+ // Create death effects
+ LK.effects.flashObject(self, 0xff0000, 500);
+ // Create particle effects for death
+ for (var p = 0; p < 6; p++) {
+ var particle = new Container();
+ var particleGraphics = particle.attachAsset('character', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ scaleX: 0.2,
+ scaleY: 0.2
+ });
+ particleGraphics.tint = 0x8B4513;
+ particle.x = self.x;
+ particle.y = self.y;
+ game.addChild(particle);
+ // Random direction for each particle
+ var angle = p / 6 * Math.PI * 2;
+ var speed = 60 + Math.random() * 40;
+ var targetX = particle.x + Math.cos(angle) * speed;
+ var targetY = particle.y + Math.sin(angle) * speed;
+ // Animate particle flying out and fading
+ tween(particle, {
+ x: targetX,
+ y: targetY,
+ scaleX: 0.05,
+ scaleY: 0.05,
+ alpha: 0,
+ rotation: Math.random() * Math.PI * 2
+ }, {
+ duration: 400 + Math.random() * 200,
+ easing: tween.easeOut,
+ onFinish: function onFinish() {
+ particle.destroy();
+ }
+ });
+ }
+ // Remove from villagers array
+ for (var i = villagers.length - 1; i >= 0; i--) {
+ if (villagers[i] === self) {
+ villagers.splice(i, 1);
+ break;
+ }
+ }
+ // Destroy villager after effects
+ LK.setTimeout(function () {
+ self.destroy();
+ }, 500);
+ };
self.update = function () {
+ if (!self.isAlive) return;
+ // Apply gravity to villager
+ var hasSupport = false;
+ if (self.gridY + 1 >= GRID_HEIGHT) {
+ hasSupport = true;
+ } else if (grid[self.gridX] && grid[self.gridX][self.gridY + 1] !== null) {
+ hasSupport = true;
+ }
+ if (!hasSupport) {
+ // Villager should fall
+ self.gravity += self.gravityAcceleration;
+ if (self.gravity > self.maxFallSpeed) {
+ self.gravity = self.maxFallSpeed;
+ }
+ // Find where villager should fall to
+ var fallToY = self.gridY;
+ for (var checkY = self.gridY + 1; checkY < GRID_HEIGHT; checkY++) {
+ if (grid[self.gridX][checkY] !== null) {
+ break;
+ }
+ fallToY = checkY;
+ }
+ // Move villager down if there's a place to fall
+ if (fallToY > self.gridY) {
+ var targetY = Math.min(fallToY, self.gridY + Math.floor(self.gravity));
+ if (targetY !== self.gridY) {
+ self.setGridPosition(self.gridX, targetY);
+ }
+ }
+ } else {
+ // Villager has support, reset gravity
+ self.gravity = 0;
+ }
self.moveTimer++;
// Simple AI movement every 3 seconds
if (self.moveTimer >= 180) {
self.moveTimer = 0;
@@ -2327,8 +2416,16 @@
game.down = function (x, y, obj) {
var gridPos = getGridPosition(x, y);
pressStartTime = LK.ticks;
isLongPress = false;
+ // Check if clicking on a villager first
+ for (var i = 0; i < villagers.length; i++) {
+ var villager = villagers[i];
+ if (villager.isAlive && villager.gridX === gridPos.x && villager.gridY === gridPos.y) {
+ villager.kill();
+ return; // Exit early if we killed a villager
+ }
+ }
// Start long press timer for breaking blocks
if (pressTimer) {
LK.clearTimeout(pressTimer);
}