Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'ReferenceError: tween is not defined' in or related to this line: 'tween(achText, {' Line Number: 1592 ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Please fix the bug: 'ReferenceError: quantumShardActive is not defined' in or related to this line: 'if (quantumShardActive) {' Line Number: 1557
User prompt
Please fix the bug: 'ReferenceError: chronostoneActive is not defined' in or related to this line: 'if (chronostoneActive) {' Line Number: 1532
User prompt
Please fix the bug: 'ReferenceError: statsTextObj is not defined' in or related to this line: 'if (statsTextObj) {' Line Number: 1509
User prompt
Please fix the bug: 'Cluster is not defined' in or related to this line: 'var cluster = new Cluster(type);' Line Number: 895
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'x')' in or related to this line: 'var tx = self.currentTarget.parent.x + self.currentTarget.x,' Line Number: 414
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'x')' in or related to this line: 'var tx = self.currentTarget.parent.x + self.currentTarget.x,' Line Number: 413
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'x')' in or related to this line: 'var tx = self.currentTarget.parent.x + self.currentTarget.x,' Line Number: 413
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'x')' in or related to this line: 'var tx = self.currentTarget.parent.x + self.currentTarget.x,' Line Number: 413
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'x')' in or related to this line: 'var tx = self.currentTarget.parent.x + self.currentTarget.x,' Line Number: 413
User prompt
Implement the new code here: /**** * PLUGINS ****/ var tween = LK.import("@upit/tween.v1"); /**** * CLASSES ****/ // Cluster – spawns multiple ore objects. var Cluster = Container.expand(function (type) { var self = Container.call(this); self.type = type; self.oreList = []; self.zIndex = 0; // Use helper to generate valid spawn position var center = getValidClusterCenter(); self.x = center.x; self.y = center.y; var cc = gameState.clusterConfig; var count = randomInt(cc.min, cc.max); for (var i = 0; i < count; i++) { var ore = new Ore(type, self); ore.x = (Math.random() - 0.5) * 120; ore.y = (Math.random() - 0.5) * 120; self.oreList.push(ore); self.addChild(ore); } // Increment individual ore mined stat when an ore is destroyed. self.notifyOreDestroyed = function (ore) { var idx = self.oreList.indexOf(ore); if (idx >= 0) { self.oreList.splice(idx, 1); } ore.destroy(); gameState.oreMined[type] = (gameState.oreMined[type] || 0) + 1; if (self.oreList.length === 0) { if (self.parent) { self.parent.removeChild(self); } var cidx = clusters.indexOf(self); if (cidx >= 0) { clusters.splice(cidx, 1); } gameState.clusterCount[type]--; var finalDelay = gameState.respawnTime; if (type === 'coal') { finalDelay *= 2; } LK.setTimeout(function () { maybeSpawnCluster(type); }, finalDelay); } }; return self; }); // Drone – moves and zaps ores. var Drone = Container.expand(function () { var self = Container.call(this); self.droneSprite = LK.getAsset('drone_asset', { anchorX: 0.5, anchorY: 0.5 }); self.addChild(self.droneSprite); self.AOE_RANGE = 150; self.droneDamage = 2; self.COOLDOWN_MAX = 60; self.cooldown = 0; var SPEED = 8, MIN_X = 50, MAX_X = 2000, MIN_Y = 50, MAX_Y = 2682; self.vx = Math.random() < 0.5 ? SPEED : -SPEED; self.vy = Math.random() < 0.5 ? SPEED : -SPEED; self.updateDrone = function () { self.x += self.vx; self.y += self.vy; if (self.x < MIN_X || self.x > MAX_X) { self.vx = -self.vx; } if (self.y < MIN_Y || self.y > MAX_Y) { self.vy = -self.vy; } if (Math.random() < 0.01) { self.vx += (Math.random() - 0.5) * 2; self.vy += (Math.random() - 0.5) * 2; var speed = Math.sqrt(self.vx * self.vx + self.vy * self.vy); if (speed > SPEED) { self.vx = self.vx / speed * SPEED; self.vy = self.vy / speed * SPEED; } } self.droneSprite.rotation += 0.1; if (self.cooldown > 0) { self.cooldown--; } else { self.tryZap(); } }; self.tryZap = function () { var hitSomething = false; clusters.forEach(function (cluster) { cluster.oreList.forEach(function (ore) { if (ore.health > 0) { var oreGlobalX = cluster.x + ore.x, oreGlobalY = cluster.y + ore.y; var dx = self.x - oreGlobalX, dy = self.y - oreGlobalY; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < self.AOE_RANGE) { var damage = self.droneDamage; var actualDamage = Math.min(damage, ore.health); var fraction = actualDamage / ore.maxHealth; var reward = Math.round(fraction * ore.getValue()); if (ore.awardedMoney + reward > ore.getValue()) { reward = ore.getValue() - ore.awardedMoney; } ore.awardedMoney += reward; gameState.money += reward; gameState.totalMoneyEarned += reward; updateUI(); ore.health -= actualDamage; hitSomething = true; spawnDroneAOE(ore); if (ore.health <= 0) { ore.cluster.notifyOreDestroyed(ore); spawnMiningParticles(ore, 5); } else { spawnMiningParticles(ore, 2); } // Drone hit floating text in red. showFloatingText(reward, 0xFF0000); } } }); }); if (hitSomething) { LK.getSound('drone_shot').play(); self.cooldown = self.COOLDOWN_MAX; } }; return self; }); // Miner – moves toward and mines the nearest ore. var Miner = Container.expand(function () { var self = Container.call(this); self.attachAsset('miner', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 5; self.currentTarget = null; self.miningRange = 25; self.miningCooldown = 0; self.miningRate = 60; self.miningDamage = 1; self.originalMiningRate = self.miningRate; self.originalMiningDamage = self.miningDamage; self.speedBoostMultiplier = 1; self.speedBoostTimer = 0; self.soulEmberStacks = 0; self.quantumPathActive = false; self.quantumPath = []; self.quantumShardValueBonus = false; self.hyperMiningActive = false; self.hyperMiningTimer = 0; self.update = function () { if (self.hyperMiningActive) { self.hyperMiningTimer--; if (self.hyperMiningTimer <= 0) { self.miningDamage = self.originalMiningDamage; self.miningRate = self.originalMiningRate; self.hyperMiningActive = false; } } if (self.speedBoostTimer > 0) { self.speedBoostTimer--; if (self.speedBoostTimer <= 0) { self.speedBoostMultiplier = 1; } } self.findNewTarget(); if (self.currentTarget) { var tx = self.currentTarget.parent.x + self.currentTarget.x, ty = self.currentTarget.parent.y + self.currentTarget.y; var dx = tx - self.x, dy = ty - self.y; var dist = Math.sqrt(dx * dx + dy * dy); var finalSpeed = self.speed * self.speedBoostMultiplier; if (dist > self.miningRange) { self.x += dx / dist * finalSpeed; self.y += dy / dist * finalSpeed; } else { self.mineOre(self.currentTarget); } } else { if (typeof LK.time !== 'undefined') { self.y += Math.sin(LK.time.elapsed / 250) * 0.5; } } }; self.findNewTarget = function () { if (self.quantumPathActive && self.quantumPath.length > 0) { self.currentTarget = self.quantumPath[0]; if (!self.currentTarget || self.currentTarget.health <= 0) { self.quantumPath.shift(); if (self.quantumPath.length === 0) { self.quantumShardValueBonus = false; self.quantumPathActive = false; self.currentTarget = null; } return; } return; } var validOre = []; clusters.forEach(function (c) { c.oreList.forEach(function (ore) { if (ore.health > 0 && (ore.tier <= gameState.currentTier || ore.type === "chronostone" || ore.type === "soulember" || ore.type === "quantumshard")) { validOre.push(ore); } }); }); if (validOre.length === 0) { self.currentTarget = null; return; } self.currentTarget = validOre.sort(function (a, b) { var aX = a.parent.x + a.x, aY = a.parent.y + a.y; var bX = b.parent.x + b.x, bY = b.parent.y + b.y; return Math.hypot(aX - self.x, aY - self.y) - Math.hypot(bX - self.x, bY - self.y); })[0]; }; self.mineOre = function (ore) { if (self.miningCooldown > 0) { self.miningCooldown--; return; } var damageDealt = self.miningDamage * gameState.pickaxeLevel * (gameState.pickaxeBaseMultiplier || 1); if (soulEmberActive && soulEmberBoostCount > 0) { damageDealt *= 2; } var actualDamage = Math.min(damageDealt, ore.health); var fraction = actualDamage / ore.maxHealth; var rewardMultiplier = (soulEmberActive && soulEmberBoostCount > 0) ? 2 : 1; var reward = Math.round(fraction * ore.getValue() * rewardMultiplier); if (ore.awardedMoney + reward > ore.getValue()) { reward = ore.getValue() - ore.awardedMoney; } ore.awardedMoney += reward; gameState.money += reward; gameState.totalMoneyEarned += reward; gameState.minerHitCount++; updateUI(); var mineSound = LK.getSound('mine_' + ore.type); if (mineSound) { mineSound.play(); } ore.health -= actualDamage; self.miningCooldown = self.miningRate; if (ore.health <= 0) { spawnMiningParticles(ore, 5); var destroySound = LK.getSound('ore_destroy_' + ore.type); if (destroySound) { destroySound.play(); } if (ore.type === "explosive" && ore.explode) { ore.explode(); if (gameState.prestigeCount >= 12 && !meteorShowerActive) { triggerMeteorShowerEffect(); } } ore.cluster.notifyOreDestroyed(ore); if (soulEmberActive && soulEmberBoostCount > 0) { soulEmberBoostCount--; showFloatingText(reward, 0xFFD700); if (soulEmberBoostCount <= 0) { soulEmberActive = false; if (soulEmberOverlay && soulEmberOverlay.parent) { soulEmberOverlay.parent.removeChild(soulEmberOverlay); soulEmberOverlay.destroy(); soulEmberOverlay = null; } soulEmberBannerShown = false; } } else { showFloatingText(reward, 0x00FF00); } if (ore.type === "chronostone" && !chronostoneActive) { triggerChronostoneEffect(); } if (ore.type === "soulember" && !soulEmberActive) { triggerSoulEmberEffect(); } if (ore.type === "quantumshard" && !quantumShardActive) { triggerQuantumShardEffect(); } } else { spawnMiningParticles(ore, 2); showFloatingText(reward, 0x00FF00); } }; self.applyChronostoneBoost = function () { self.speedBoostMultiplier *= 2; self.speedBoostTimer = 30 * 60; }; self.triggerQuantumShardMode = function () { self.quantumShardValueBonus = true; self.quantumPathActive = true; self.quantumPath = []; game.pauseForQuantumSelection(); }; return self; }); // MiniMiner – spawned by Quantum Shard effect. var MiniMiner = Container.expand(function (parentMiner) { var self = Container.call(this); self.attachAsset('miner', { anchorX: 0.5, anchorY: 0.5, scale: 0.5 }); self.speed = parentMiner.speed * 1.2; self.miningDamage = parentMiner.miningDamage; self.miningRate = parentMiner.miningRate; self.currentTarget = null; self.update = function () { if (self.currentTarget) { var tx = self.currentTarget.parent.x + self.currentTarget.x, ty = self.currentTarget.parent.y + self.currentTarget.y; var dx = tx - self.x, dy = ty - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 25) { self.x += dx / dist * self.speed; self.y += dy / dist * self.speed; } else { self.currentTarget.health -= self.miningDamage; showFloatingText(Math.round(self.miningDamage), 0xFF69B4); if (self.currentTarget.health <= 0) { self.currentTarget.cluster.notifyOreDestroyed(self.currentTarget); self.currentTarget = null; } } } else { var validOre = []; clusters.forEach(function (c) { c.oreList.forEach(function (ore) { if (ore.health > 0) { validOre.push(ore); } }); }); if (validOre.length > 0) { self.currentTarget = validOre[Math.floor(Math.random() * validOre.length)]; } } }; return self; }); // Ore – represents a single ore. var Ore = Container.expand(function (type, cluster) { var self = Container.call(this); self.type = type; self.cluster = cluster; self.zIndex = 0; var typeList = ['coal', 'iron', 'gold', 'diamond', 'sapphire', 'emerald', 'ruby']; self.tier = (typeList.indexOf(type) >= 0) ? typeList.indexOf(type) + 1 : 999; self.baseValue = oreData[type].baseValue; self.maxHealth = oreData[type].baseHealth; self.health = self.maxHealth; self.attachAsset(oreData[type].assetId, { anchorX: 0.5, anchorY: 0.5 }); // Health bar using the new health_bar asset. self.healthBar = LK.getAsset('health_bar', { width: 120, height: 20, color: 0x00FF00, anchorX: 0.5, anchorY: 0.5 }); self.healthBar.x = 0; self.healthBar.y = -70; self.addChild(self.healthBar); self.awardedMoney = 0; self.lastTapTime = 0; self.interactive = true; self.buttonMode = true; self.down = function () { var currentTime = (typeof LK.time !== 'undefined') ? LK.time.elapsed : Date.now(); if (currentTime - self.lastTapTime < 1) { return; } self.lastTapTime = currentTime; var hitSound = LK.getSound('mine_' + self.type); if (hitSound) { hitSound.play(); } var damage = gameState.tapDamage; var actualDamage = Math.min(damage, self.health); var fraction = actualDamage / self.maxHealth; var reward = Math.round(fraction * self.getValue()); if (self.awardedMoney + reward > self.getValue()) { reward = self.getValue() - self.awardedMoney; } self.awardedMoney += reward; gameState.money += reward; gameState.totalMoneyEarned += reward; gameState.tapCount++; updateUI(); self.health -= actualDamage; spawnMiningParticles(self, 2); if (self.health <= 0) { var destroySound = LK.getSound('ore_destroy_' + self.type); if (destroySound) { destroySound.play(); } if (self.type === "chronostone" && !chronostoneActive) { triggerChronostoneEffect(); } if (self.type === "soulember" && !soulEmberActive) { triggerSoulEmberEffect(); } if (self.type === "quantumshard" && !quantumShardActive) { triggerQuantumShardEffect(); } self.cluster.notifyOreDestroyed(self); showFloatingText(reward, 0x0000FF); } }; // If special ore, add pulsing glow. if (["chronostone", "soulember", "quantumshard"].indexOf(type) >= 0) { var _pulseGlow2 = function () { tween(glow, { alpha: 1 }, { duration: 1000, onFinish: function () { tween(glow, { alpha: 0.5 }, { duration: 1000, onFinish: _pulseGlow2 }); }}); }; var glow = LK.getAsset('glowing_line_asset', { anchorX: 0.5, anchorY: 0.5 }); glow.alpha = 0.5; self.addChildAt(glow, 0); _pulseGlow2(); } if (type === "explosive") { self.explode = function () { var explosionRadius = 100; clusters.forEach(function (cluster) { cluster.oreList.forEach(function (otherOre) { if (otherOre !== self && otherOre.health > 0) { var oreGlobalX = cluster.x + otherOre.x, oreGlobalY = cluster.y + otherOre.y; var dx = self.parent.x + self.x - oreGlobalX, dy = self.parent.y + self.y - oreGlobalY; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < explosionRadius) { otherOre.health -= 50; if (otherOre.health <= 0) { var baseValue = otherOre.getValue(); gameState.money += baseValue; updateUI(); otherOre.cluster.notifyOreDestroyed(otherOre); spawnMiningParticles(otherOre, 5); } else { spawnMiningParticles(otherOre, 2); } } } }); }); screenShake(500, 10); }; } self.getValue = function () { var val = self.baseValue * gameState.oreMultipliers[self.type]; return Math.round(val / 2) * 2; }; return self; }); // SingleOre – for special ores that spawn individually. var SingleOre = Container.expand(function (type) { var self = Container.call(this); self.type = type; var ore = new Ore(type, self); ore.x = 0; ore.y = 0; self.addChild(ore); self.notifyOreDestroyed = function (ore) { ore.destroy(); gameState.oreMined[type] = (gameState.oreMined[type] || 0) + 1; if (self.parent) { self.parent.removeChild(self); } specialOres[type] = null; }; return self; }); /**** * HELPER FUNCTIONS ****/ function getValidClusterCenter() { var uiMargin = 200; var minX = uiMargin, maxX = 2048 - uiMargin; var minY = uiMargin, maxY = 2732 - uiMargin; return { x: randomInt(minX, maxX), y: randomInt(minY, maxY) }; } function randomInt(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; } function spawnMiningParticles(ore, num) { for (var i = 0; i < num; i++) { var p = LK.getAsset('mining_particle', { anchorX: 0.5, anchorY: 0.5 }); if (ore.parent) { p.x = ore.parent.x + ore.x; p.y = ore.parent.y + ore.y; } else { p.x = ore.x; p.y = ore.y; } if (["chronostone", "soulember", "quantumshard"].indexOf(ore.type) >= 0) { p.tint = oreData[ore.type].color || 0xffffff; } p.vx = (Math.random() - 0.5) * 10; p.vy = (Math.random() - 0.5) * 10; p.alpha = 1; p.zIndex = -1; tween(p, { alpha: 0, y: p.y - 50 }, { duration: 1000, onFinish: function () { p.destroy(); } }); game.addChild(p); } } function interpolateColor(c1, c2, f) { var r1 = (c1 >> 16) & 0xFF, g1 = (c1 >> 8) & 0xFF, b1 = c1 & 0xFF; var r2 = (c2 >> 16) & 0xFF, g2 = (c2 >> 8) & 0xFF, b2 = c2 & 0xFF; var r = Math.round(r1 + f * (r2 - r1)), g = Math.round(g1 + f * (g2 - g1)), b = Math.round(b1 + f * (b2 - b1)); return (r << 16) | (g << 8) | b; } function screenShake(duration, magnitude) { var originalX = game.x, originalY = game.y, shakeInterval = 50, elapsed = 0; var shake = setInterval(function () { elapsed += shakeInterval; game.x = originalX + (Math.random() - 0.5) * magnitude; game.y = originalY + (Math.random() - 0.5) * magnitude; if (elapsed >= duration) { clearInterval(shake); game.x = originalX; game.y = originalY; } }, shakeInterval); } function spawnDroneAOE(ore) { var effect = LK.getAsset('drone_aoe_effect', { anchorX: 0.5, anchorY: 0.5 }); if (ore.parent) { effect.x = ore.parent.x + ore.x; effect.y = ore.parent.y + ore.y; } else { effect.x = ore.x; effect.y = ore.y; } effect.alpha = 1; effect.zIndex = 1; game.addChild(effect); tween(effect, { alpha: 0 }, { duration: 500, onFinish: function () { effect.destroy(); } }); } /**** * SPECIAL EFFECT FUNCTIONS ****/ function showEventBanner(text) { var banner = new Text2(text, { size: 60, fill: 0x000000, stroke: 0xFFFFFF, strokeThickness: 4, fontWeight: 'bold', align: 'center' }); banner.anchor.set(0.5); banner.x = 2048 / 2; banner.y = 200; game.addChild(banner); tween(banner, { alpha: 0, y: banner.y - 50 }, { duration: 3000, onFinish: function () { banner.destroy(); } }); } function triggerChronostoneEffect() { chronostoneActive = true; chronostoneTimer = 30 * 60; if (!chronostoneBannerShown) { showEventBanner("Chronostone Speed Boost"); chronostoneBannerShown = true; } if (!chronostoneOverlay) { chronostoneOverlay = LK.getAsset('chronostone_overlay', { anchorX: 0.5, anchorY: 0.5, alpha: 0.5 }); chronostoneOverlay.x = 2048 / 2; chronostoneOverlay.y = 2732 / 2; game.addChild(chronostoneOverlay); } if (!chronostoneTimerText) { chronostoneTimerText = new Text2("30", { size: 50, fill: 0x000000, stroke: 0xFFFFFF, strokeThickness: 4, fontWeight: 'bold' }); chronostoneTimerText.x = 50; chronostoneTimerText.y = 50; game.addChild(chronostoneTimerText); } if (miner) { miner.speedBoostMultiplier *= 2; miner.speedBoostTimer = chronostoneTimer; } } function triggerSoulEmberEffect() { soulEmberActive = true; if (!soulEmberBannerShown) { showEventBanner("Soul Ember +Dmg/+$"); soulEmberBannerShown = true; } if (!soulEmberOverlay) { soulEmberOverlay = LK.getAsset('soulember_overlay', { anchorX: 0.5, anchorY: 0.5, alpha: 0.5 }); soulEmberOverlay.x = 2048 / 2; soulEmberOverlay.y = 2732 / 2; game.addChild(soulEmberOverlay); } var drain = gameState.money * 0.10; gameState.money -= drain; updateUI(); showFloatingText("-$" + Math.floor(drain).toLocaleString(), 0xFF0000); soulEmberBoostCount = 10; gameState.pickaxeBaseMultiplier *= 1.5; } function triggerQuantumShardEffect() { quantumShardActive = true; quantumShardTimer = 10 * 60; if (!quantumShardBannerShown) { showEventBanner("Quantum Split Miner Split"); quantumShardBannerShown = true; } if (!quantumShardOverlay) { quantumShardOverlay = LK.getAsset('quantumshard_overlay', { anchorX: 0.5, anchorY: 0.5, alpha: 0.5 }); quantumShardOverlay.x = 2048 / 2; quantumShardOverlay.y = 2732 / 2; game.addChild(quantumShardOverlay); } for (var i = 0; i < 5; i++) { var mini = new MiniMiner(miner); mini.x = miner.x + (Math.random() - 0.5) * 100; mini.y = miner.y + (Math.random() - 0.5) * 100; miniMiners.push(mini); game.addChild(mini); } } function triggerMeteorShowerEffect() { meteorShowerActive = true; if (!meteorShowerBannerShown) { showEventBanner("Meteor Shower"); meteorShowerBannerShown = true; } var numMeteors = Math.floor(Math.random() * 2) + 3; for (var i = 0; i < numMeteors; i++) { spawnMeteor(); } LK.setTimeout(function () { meteorShowerActive = false; meteorShowerBannerShown = false; }, 5000); } function spawnMeteor() { var meteor = LK.getAsset('meteor_shower', { anchorX: 0.5, anchorY: 0.5 }); meteor.x = 100 + Math.random() * (2048 - 200); meteor.y = -100; game.addChild(meteor); var target = getValidClusterCenter(); tween(meteor, { x: target.x, y: target.y }, { duration: 1000, onFinish: function () { var aoe = LK.getAsset('meteor_aoe', { anchorX: 0.5, anchorY: 0.5, alpha: 0.7 }); aoe.x = target.x; aoe.y = target.y; game.addChild(aoe); clusters.forEach(function (cluster) { cluster.oreList.forEach(function (ore) { var oreGlobalX = cluster.x + ore.x, oreGlobalY = cluster.y + ore.y; if (Math.abs(oreGlobalX - target.x) < 50 && Math.abs(oreGlobalY - target.y) < 50) { var damage = 100; ore.health -= damage; showFloatingText("Meteor: " + damage, 0xFFFFFF); if (ore.health <= 0) { ore.cluster.notifyOreDestroyed(ore); } } }); }); tween(aoe, { alpha: 0 }, { duration: 1000, onFinish: function () { aoe.destroy(); } }); meteor.destroy(); } }); } // UI Helper: Floating Text. function showFloatingText(amount, color) { var txt = new Text2("+" + amount, { size: 40, fill: color, stroke: color, strokeThickness: 4, align: 'center', fontWeight: 'bold' }); var offsetX = (Math.random() - 0.5) * 50; var offsetY = (Math.random() - 0.5) * 50; if (color === 0xFF0000) { offsetX += 300; } else if (color === 0x0000FF) { offsetX -= 300; } else if (color === 0xFF69B4) { offsetY += 50; } txt.x = moneyDisplay.x + moneyDisplay.width / 2 + offsetX; txt.y = moneyDisplay.y + moneyDisplay.height + offsetY; game.addChild(txt); tween(txt, { alpha: 0, y: txt.y - 20 }, { duration: 1000, onFinish: function () { txt.destroy(); } }); } /**** * SPECIAL SPAWNING FUNCTIONS ****/ function maybeSpawnCluster(type) { if (type === "chronostone" || type === "soulember" || type === "quantumshard") { return; } var typeList = ['coal', 'iron', 'gold', 'diamond', 'sapphire', 'emerald', 'ruby']; if (typeList.indexOf(type) >= 0) { var tIndex = typeList.indexOf(type) + 1; if (tIndex > gameState.currentTier) { return; } } if (gameState.clusterCount[type] >= gameState.maxClustersPerType) { return; } var cluster = new Cluster(type); game.addChild(cluster); clusters.push(cluster); gameState.clusterCount[type]++; } function maybeSpawnSpecialOres() { var specialTypes = ['chronostone', 'soulember', 'quantumshard']; specialTypes.forEach(function (type) { if (!specialOres[type]) { if (type === 'chronostone' && gameState.prestigeCount >= 3) { spawnSingleOre(type); } if (type === 'soulember' && gameState.prestigeCount >= 5) { spawnSingleOre(type); } if (type === 'quantumshard' && gameState.prestigeCount >= 8) { spawnSingleOre(type); } } }); } function spawnSingleOre(type) { var singleOre = new SingleOre(type); var pos = getValidClusterCenter(); singleOre.x = pos.x; singleOre.y = pos.y; game.addChild(singleOre); specialOres[type] = singleOre; } /**** * PRESTIGE & BACKGROUND TRANSITION ****/ function getPrestigeRequirement() { return 1e9 * Math.pow(2, gameState.prestigeCount); } function canPrestige() { return gameState.money >= getPrestigeRequirement(); } function calculatePrestigeShards() { return 1; } function doPrestige() { for (var i = clusters.length - 1; i >= 0; i--) { var c = clusters[i]; c.removeChildren(); if (c.parent) { c.parent.removeChild(c); } clusters.splice(i, 1); } droneObjects.forEach(function (d) { if (d.parent) { d.parent.removeChild(d); } }); droneObjects = []; droneSprites.forEach(function (ds) { if (ds.parent) { ds.parent.removeChild(ds); } }); droneSprites = []; var shards = calculatePrestigeShards(); gameState.prestigeCurrency += shards; gameState.prestigeCount++; gameState.money = 0; gameState.currentTier = 1; for (var key in gameState.clusterCount) { gameState.clusterCount[key] = 0; } resetUpgrades(); gameState.droneLevel = 0; if (miner) { miner.miningRate = miner.originalMiningRate; } gamePaused = true; handleBackgroundTransition(); updateUI(); } function resetUpgrades() { gameState.oreMultipliers = { coal:1, iron:1, gold:1, diamond:1, sapphire:1, emerald:1, ruby:1, chronostone:1, soulember:1, quantumshard:1 }; gameState.pickaxeLevel = 1; gameState.pickaxeBaseMultiplier = 1; gameState.tapDamage = 1; gameState.respawnTime = 3000; gameState.clusterUpgradeTier = 0; for (var key in oreUpgrades) { oreUpgrades[key].forEach(function (upg) { if (upg.initCost === undefined) { upg.initCost = upg.cost; } upg.cost = upg.initCost; upg.level = 0; upg.purchased = false; }); } generalUpgrades.forEach(function (upg) { if (upg.initCost === undefined) { upg.initCost = upg.cost; } upg.cost = upg.initCost; upg.level = 0; upg.purchased = false; }); droneUpgrades.forEach(function (upg) { if (upg.initCost === undefined) { upg.initCost = upg.cost; } upg.cost = upg.initCost; upg.level = 0; upg.purchased = false; }); } /* --- UPDATED BACKGROUND TRANSITION FUNCTION --- */ function handleBackgroundTransition() { // Determine which background asset to use. var bgAssetId; if (gameState.prestigeCount >= 8) { bgAssetId = 'background_tier8'; } else if (gameState.prestigeCount >= 5) { bgAssetId = 'background_tier5'; } else if (gameState.prestigeCount >= 3) { bgAssetId = 'background_tier3'; } else { bgAssetId = 'background'; } // Create the new background off-screen (below current view). var newBg = LK.getAsset(bgAssetId, { anchorX: 0.5, anchorY: 0.5 }); newBg.x = 2048 / 2; newBg.y = 2732 + 2732 / 2; // start off-screen below newBg.zIndex = -100; game.addChildAt(newBg, 0); // If no current background exists, immediately set newBg as current. if (!currentBackground) { newBg.y = 2732 / 2; currentBackground = newBg; gamePaused = false; initialSpawn(); return; } var dur = 3000; // Tween current (old) background upward and off-screen. tween(currentBackground, { y: currentBackground.y - 2732 }, { duration: dur, onFinish: function () { if (currentBackground && currentBackground.parent) { currentBackground.parent.removeChild(currentBackground); } } }); // Tween new background upward into view. tween(newBg, { y: 2732 / 2 }, { duration: dur, onFinish: function () { currentBackground = newBg; gamePaused = false; initialSpawn(); } }); } var clusters = []; var currentBackground = null; var nextBackground = null; var miner = null; var droneObjects = []; var droneSprites = []; var prestigeMainButton = null; var gamePaused = false; /**** * SPAWN FUNCTIONS ****/ function initialSpawn() { if (gamePaused) { return; } var allTypes = ['coal', 'iron', 'gold', 'diamond', 'sapphire', 'emerald', 'ruby']; allTypes.forEach(function (type, idx) { var t = idx + 1; if (t <= gameState.currentTier) { for (var i = 0; i < gameState.maxClustersPerType; i++) { maybeSpawnCluster(type); } } }); maybeSpawnSpecialOres(); } function updateDroneObjects() { while (droneObjects.length < gameState.droneLevel) { var d = new Drone(); d.x = 200 + Math.random() * (2048 - 400); d.y = 200 + Math.random() * (2732 - 400); droneObjects.push(d); game.addChild(d); } } function updateDroneSprites() { while (droneSprites.length < gameState.droneLevel) { var drone = LK.getAsset('drone_asset', { anchorX: 0.5, anchorY: 0.5 }); drone.x = 100 + droneSprites.length * 90; drone.y = 200; droneSprites.push(drone); game.addChild(drone); } } /**** * UPGRADE DATA ****/ // (Upgrade data remains unchanged; see your current code for details) /**** * UI ****/ var upgradeMenu = new Container(); upgradeMenu.zIndex = 10000; var tooltip = new Text2('', { size: 40, fill: 0xFFFFFF, stroke: 0x000000, strokeThickness: 4 }); game.addChild(tooltip); var moneyDisplay = new Text2('$0', { size: 80, fill: 0xFFFFFF, fontWeight: 'bold', stroke: 0x000000, strokeThickness: 4 }); moneyDisplay.x = 2048 / 2 - moneyDisplay.width / 2; moneyDisplay.y = 50; game.addChild(moneyDisplay); var prestigeDisplay = new Text2('Prestige: 0', { size: 50, fill: 0xFFFFFF, fontWeight: 'bold', stroke: 0x000000, strokeThickness: 4 }); prestigeDisplay.x = 250; prestigeDisplay.y = 50; game.addChild(prestigeDisplay); var shopOpenButton = LK.getAsset('shop_icon', { anchorX: 0.5, anchorY: 0.5 }); shopOpenButton.x = 2048 - 150; shopOpenButton.y = 2732 - 150; shopOpenButton.down = function () { createMainUpgradeMenu(); game.addChild(upgradeMenu); if (upgradeMenu.parent) { upgradeMenu.parent.setChildIndex(upgradeMenu, upgradeMenu.parent.children.length - 1); } }; game.addChild(shopOpenButton); var addMoneyButton = LK.getAsset('test_money_button', { anchorX: 0.5, anchorY: 0.5 }); addMoneyButton.x = 200; addMoneyButton.y = 2732 - 300; addMoneyButton.down = function () { gameState.money += 5000000000000; updateUI(); }; game.addChild(addMoneyButton); /**** * UPGRADE MODAL HELPER ****/ function showUpgradeModal(upg, btn, callback) { var modal = new Container(); var bg = LK.getAsset('upgrade_popup_bg', { anchorX: 0.5, anchorY: 0.5 }); modal.addChild(bg); var nextCost = upg.multi ? Math.floor(upg.cost * 2) : upg.cost; var textStr = upg.effect + "\nCost: $" + upg.cost; if (upg.multi) { textStr += " Next: $" + nextCost; } var desc = new Text2(textStr, { size: 35, fill: 0x000000, stroke: 0x000000, strokeThickness: 4, align: 'center', fontWeight: 'bold' }); desc.anchor.set(0.5); desc.y = -50; modal.addChild(desc); var upgradeBtn = LK.getAsset('upgrade_confirm_button', { anchorX: 0.5, anchorY: 0.5 }); upgradeBtn.x = -100; upgradeBtn.y = 50; modal.addChild(upgradeBtn); var upgradeTxt = new Text2("Upgrade", { size: 35, fill: 0x000000, stroke: 0xFFFFFF, strokeThickness: 4, align: 'center', fontWeight: 'bold' }); upgradeTxt.anchor.set(0.5); upgradeTxt.x = upgradeBtn.x; upgradeTxt.y = upgradeBtn.y; modal.addChild(upgradeTxt); var cancelBtn = LK.getAsset('cancelButton', { anchorX: 0.5, anchorY: 0.5 }); cancelBtn.x = 100; cancelBtn.y = 50; modal.addChild(cancelBtn); modal.x = btn.x; modal.y = btn.y - 150; upgradeMenu.addChild(modal); if (upgradeMenu.parent) { upgradeMenu.parent.setChildIndex(upgradeMenu, upgradeMenu.parent.children.length - 1); } upgradeBtn.down = function () { callback(true); modal.destroy(); }; cancelBtn.down = function () { callback(false); modal.destroy(); }; upgradeMenu.down = function (event) { modal.destroy(); }; } /**** * PRESTIGE MODAL ****/ function showPrestigeModal() { var modal = new Container(); var popup = LK.getAsset('prestige_popup', { anchorX: 0.5, anchorY: 0.5 }); modal.addChild(popup); var req = getPrestigeRequirement(); var prompt = new Text2("Prestige?\nYou need: $" + req.toLocaleString() + "\nYou have: $" + Math.floor(gameState.money).toLocaleString(), { size: 40, fill: 0xFFFFFF, stroke: 0x000000, strokeThickness: 4, align: 'center', fontWeight: 'bold' }); prompt.anchor.set(0.5); modal.addChild(prompt); popup.x = 0; popup.y = 0; prompt.x = 0; prompt.y = -30; var yesBtn = LK.getAsset('yes_button', { anchorX: 0.5, anchorY: 0.5 }); yesBtn.x = -100; yesBtn.y = 60; modal.addChild(yesBtn); var noBtn = LK.getAsset('cancelButton', { anchorX: 0.5, anchorY: 0.5 }); noBtn.x = 100; noBtn.y = 60; modal.addChild(noBtn); modal.x = 2048 / 2; modal.y = 2732 / 2; upgradeMenu.addChild(modal); yesBtn.down = function () { if (canPrestige()) { doPrestige(); modal.destroy(); upgradeMenu.removeChild(modal); } }; noBtn.down = function () { modal.destroy(); upgradeMenu.removeChild(modal); }; upgradeMenu.down = function (event) { modal.destroy(); }; } /**** * MAIN UPGRADE MENU ****/ function createMainUpgradeMenu() { upgradeMenu.removeChildren(); subUpgradeItemRefs = []; var menuBg = LK.getAsset('rectangle', { width: 1800, height: 2200, color: 0x2a2a2a, anchorX: 0.5, anchorY: 0.5 }); menuBg.alpha = 0.9; menuBg.x = 2048 / 2; menuBg.y = 2732 / 2 + 50; upgradeMenu.addChild(menuBg); var categories = [ { name: 'Coal Upgrades', type: 'coal' }, { name: 'Iron Upgrades', type: 'iron' }, { name: 'Gold Upgrades', type: 'gold' }, { name: 'Diamond Upgrades', type: 'diamond' }, { name: 'Sapphire Upgrades', type: 'sapphire' }, { name: 'Emerald Upgrades', type: 'emerald' }, { name: 'Ruby Upgrades', type: 'ruby' }, { name: 'General Upgrades', type: 'general' }, { name: 'Drones', type: 'drones' }, { name: 'Achievements', type: 'achievements' }, { name: 'Prestige', type: 'prestige' }, { name: 'Game Stats', type: 'stats' } ]; var colSpacing = 400, rowSpacing = 300; for (var i = 0; i < categories.length; i++) { var col = i % 2, row = Math.floor(i / 2); var x = menuBg.x + (col === 0 ? -colSpacing : colSpacing); var y = menuBg.y - 800 + row * rowSpacing; var btn = LK.getAsset('buy_button', { anchorX: 0.5, anchorY: 0.5 }); btn.x = x; btn.y = y; upgradeMenu.addChild(btn); var txt = new Text2(categories[i].name, { size: 50, fill: 0x000000, stroke: 0xFFFFFF, strokeThickness: 4, align: 'center', fontWeight: 'bold' }); txt.anchor.set(0.5); txt.x = btn.x; txt.y = btn.y; upgradeMenu.addChild(txt); btn.down = function (cat) { return function (event) { event.stopPropagation && event.stopPropagation(); hideUpgradeDesc(); if (cat.type === 'general') { createSubUpgradeMenu('General Upgrades', generalUpgrades); } else if (cat.type === 'drones') { createSubUpgradeMenu('Drone Upgrades', droneUpgrades); } else if (cat.type === 'achievements') { createAchievementsMenu(); } else if (cat.type === 'prestige') { createPrestigeMenu(); } else if (cat.type === 'stats') { createStatsMenu(); } else { createSubUpgradeMenu(cat.name, oreUpgrades[cat.type]); } }; }(categories[i]); } var closeBtn = LK.getAsset('cancelButton', { anchorX: 0.5, anchorY: 0.5 }); closeBtn.x = menuBg.x + 750; closeBtn.y = menuBg.y - 950; closeBtn.down = function () { game.removeChild(upgradeMenu); }; upgradeMenu.addChild(closeBtn); upgradeMenu.down = function (event) { hideUpgradeDesc(); }; if (upgradeMenu.parent) { upgradeMenu.parent.setChildIndex(upgradeMenu, upgradeMenu.parent.children.length - 1); } } var subUpgradeItemRefs = []; function createSubUpgradeMenu(title, upgList) { upgradeMenu.removeChildren(); subUpgradeItemRefs = []; var menuBg = LK.getAsset('rectangle', { width: 1800, height: 2200, color: 0x2a2a2a, anchorX: 0.5, anchorY: 0.5 }); menuBg.alpha = 0.9; menuBg.x = 2048 / 2; menuBg.y = 2732 / 2 + 50; upgradeMenu.addChild(menuBg); var titleText = new Text2(title, { size: 60, fill: 0x000000, stroke: 0xFFFFFF, strokeThickness: 4, align: 'center', fontWeight: 'bold' }); titleText.anchor.set(0.5); titleText.x = menuBg.x; titleText.y = menuBg.y - 1000; upgradeMenu.addChild(titleText); var startY = menuBg.y - 800, colSpacing = 400; for (var i = 0; i < upgList.length; i++) { var col = i % 2, row = Math.floor(i / 2); var btn = LK.getAsset('buy_button', { anchorX: 0.5, anchorY: 0.5 }); btn.x = menuBg.x + (col === 0 ? -colSpacing : colSpacing); btn.y = startY + row * 250; upgradeMenu.addChild(btn); var displayName = upgList[i].name; if (typeof upgList[i].level === 'number' && upgList[i].level > 0) { displayName += " (Lv " + upgList[i].level + ")"; } var txt = new Text2(displayName + "\nCost: $" + upgList[i].cost, { size: 45, fill: 0x000000, stroke: 0xFFFFFF, strokeThickness: 4, align: 'center', fontWeight: 'bold' }); txt.anchor.set(0.5); txt.x = btn.x; txt.y = btn.y; upgradeMenu.addChild(txt); btn.down = function (upg, btn) { return function (event) { event.stopPropagation && event.stopPropagation(); showUpgradeModal(upg, btn, function (confirmed) { if (confirmed && canPurchaseUpgrade(upgList, upg)) { gameState.money -= upg.cost; upg.purchased = true; upg.action(); updateUI(); createSubUpgradeMenu(title, upgList); } }); }; }(upgList[i], btn); subUpgradeItemRefs.push({ upgList: upgList, upgrade: upgList[i], textObj: txt }); } var backBtn = LK.getAsset('cancelButton', { anchorX: 0.5, anchorY: 0.5 }); backBtn.x = menuBg.x + 700; backBtn.y = menuBg.y - 1000; backBtn.down = function () { createMainUpgradeMenu(); }; upgradeMenu.addChild(backBtn); upgradeMenu.down = function (event) { hideUpgradeDesc(); }; } function canPurchaseUpgrade(upgList, upg) { if (upg.requires) { var needed = upgList.find(function (u) { return u.id === upg.requires; }); if (!needed || !needed.purchased) { return false; } } if (upg.multi && upg.maxLevel !== undefined && upg.level >= upg.maxLevel) { return false; } if (!upg.multi && upg.purchased) { return false; } if (gameState.money < upg.cost) { return false; } return true; } /**** * GAME LOOP ****/ var quantumSelectTimer = 0, quantumSelectionActive = false; game.update = function () { if (!gamePaused && miner) { miner.update(); } for (var i = 0; i < droneObjects.length; i++) { droneObjects[i].updateDrone(); } if (typeof LK.time !== 'undefined' && LK.time.elapsed % 60 === 0) { droneDamageTick(); } clusters.forEach(function (cluster) { cluster.oreList.forEach(function (ore) { if (ore.health > 0) { var fraction = ore.health / ore.maxHealth; ore.healthBar.width = 120 * fraction; ore.healthBar.fill = interpolateColor(0xFF0000, 0x00FF00, fraction); ore.alpha = fraction; } }); }); if (upgradeMenu.parent) { subUpgradeItemRefs.forEach(function (ref) { var upg = ref.upgrade; var canBuy = canPurchaseUpgrade(ref.upgList, upg); if (ref.textObj && ref.textObj.style) { ref.textObj.style.fill = canBuy ? 0xFFFFFF : 0x666666; } }); } // --- Updated dynamic Game Stats --- if (statsTextObj) { var statsText = ""; statsText += "Total Money Earned: $" + gameState.totalMoneyEarned.toLocaleString() + "\n"; var achievedCount = achievements.filter(function (a) { return a.achieved; }).length; statsText += "Achievements: " + achievedCount + "/" + achievements.length + "\n"; statsText += "Prestige Count: " + gameState.prestigeCount + "\n"; var timePlayed = Math.floor((Date.now() - gameState.startTime) / 1000); statsText += "Time Played: " + timePlayed + " sec\n"; statsText += "Ore Taps: " + gameState.tapCount + "\n"; statsText += "Miner Hits: " + gameState.minerHitCount + "\n"; var fullyUpgraded = 0; for (var key in oreUpgrades) { oreUpgrades[key].forEach(function (upg) { if (upg.level >= upg.maxLevel) { fullyUpgraded++; } }); } statsText += "Fully Upgraded Ore Upgrades: " + fullyUpgraded + "\n"; statsTextObj.setText(statsText); } if (chronostoneActive) { chronostoneTimer--; if (chronostoneTimerText) { var secondsLeft = Math.ceil(chronostoneTimer / 60); chronostoneTimerText.setText(secondsLeft.toString()); } if (chronostoneTimer <= 0) { chronostoneActive = false; if (chronostoneOverlay && chronostoneOverlay.parent) { chronostoneOverlay.parent.removeChild(chronostoneOverlay); chronostoneOverlay.destroy(); chronostoneOverlay = null; } if (chronostoneTimerText && chronostoneTimerText.parent) { chronostoneTimerText.parent.removeChild(chronostoneTimerText); chronostoneTimerText.destroy(); chronostoneTimerText = null; } if (miner) { miner.speedBoostMultiplier /= 2; } chronostoneBannerShown = false; } } if (quantumShardActive) { quantumShardTimer--; miniMiners.forEach(function (mini) { mini.update(); }); if (quantumShardTimer <= 0) { miniMiners.forEach(function (mini) { if (mini.parent) { mini.parent.removeChild(mini); } }); miniMiners = []; quantumShardActive = false; if (quantumShardOverlay && quantumShardOverlay.parent) { quantumShardOverlay.parent.removeChild(quantumShardOverlay); quantumShardOverlay.destroy(); quantumShardOverlay = null; } quantumShardBannerShown = false; } } achievements.forEach(function (ach) { if (!ach.achieved && ach.condition()) { ach.achieved = true; var achText = new Text2("Achievement Unlocked: " + ach.name, { size: 40, fill: 0xFFFF00, stroke: 0x000000, strokeThickness: 4, fontWeight: 'bold' }); achText.x = 2048 / 2; achText.y = 100; game.addChild(achText); tween(achText, { alpha: 0 }, { duration: 2000, onFinish: function () { achText.destroy(); } }); } }); if (canPrestige()) { if (!prestigeMainButton) { prestigeMainButton = LK.getAsset('prestige_main_button', { anchorX: 0.5, anchorY: 0.5 }); prestigeMainButton.x = 150; prestigeMainButton.y = 2732 - 150; prestigeMainButton.down = function () { doPrestige(); if (prestigeMainButton && prestigeMainButton.parent) { prestigeMainButton.parent.removeChild(prestigeMainButton); prestigeMainButton = null; } }; game.addChild(prestigeMainButton); } } else { if (prestigeMainButton) { if (prestigeMainButton.parent) { prestigeMainButton.parent.removeChild(prestigeMainButton); } prestigeMainButton = null; } } if (upgradeMenu && upgradeMenu.parent) { upgradeMenu.parent.setChildIndex(upgradeMenu, upgradeMenu.parent.children.length - 1); } }; function droneDamageTick() { var dps = getDroneDPS(); if (dps <= 0) { return; } var allValidOres = []; clusters.forEach(function (c) { c.oreList.forEach(function (ore) { if (ore.health > 0 && ore.tier <= gameState.currentTier) { allValidOres.push(ore); } }); }); if (allValidOres.length === 0) { return; } var damageRemaining = dps; while (damageRemaining > 0 && allValidOres.length > 0) { var randomIndex = Math.floor(Math.random() * allValidOres.length); var ore = allValidOres[randomIndex]; var chunk = Math.min(damageRemaining, 10); ore.health -= chunk; damageRemaining -= chunk; if (ore.health <= 0) { var baseValue = ore.getValue(); gameState.money += baseValue; updateUI(); ore.cluster.notifyOreDestroyed(ore); spawnMiningParticles(ore, 5); allValidOres.splice(randomIndex, 1); } } } /**** * UI REFRESH & SAVE/LOAD ****/ function updateUI() { moneyDisplay.setText("$" + Math.floor(gameState.money).toLocaleString()); moneyDisplay.x = 2048 / 2 - moneyDisplay.width / 2; prestigeDisplay.setText("Prestige: " + gameState.prestigeCount); } LK.saveGame = function () { return gameState; }; LK.loadGame = function (data) { gameState = data; updateUI(); }; /**** * START GAME ****/ function startGame() { currentBackground = LK.getAsset('background', { anchorX: 0.5, anchorY: 0.5 }); currentBackground.x = 2048 / 2; currentBackground.y = 2732 / 2; currentBackground.zIndex = -100; game.addChildAt(currentBackground, 0); miner = new Miner(); miner.x = 2048 / 2; miner.y = 2732 / 2; game.addChild(miner); initialSpawn(); updateUI(); } startGame(); game.pauseForQuantumSelection = function () { quantumSelectionActive = true; quantumSelectTimer = 0; }; /**** * UPDATED GAME STATS MENU * - Removed left static ore column. * - Now shows one centered, dynamically updated, bold and outlined text block. ****/ function createStatsMenu() { upgradeMenu.removeChildren(); var menuBg = LK.getAsset('rectangle', { width: 1800, height: 2200, color: 0x222222, anchorX: 0.5, anchorY: 0.5 }); menuBg.alpha = 0.9; menuBg.x = 2048 / 2; menuBg.y = 2732 / 2 + 50; upgradeMenu.addChild(menuBg); var titleText = new Text2("Game Stats", { size: 60, fill: 0x000000, stroke: 0xFFFFFF, strokeThickness: 4, align: "center", fontWeight: "bold" }); titleText.anchor.set(0.5); titleText.x = menuBg.x; titleText.y = menuBg.y - 1000; upgradeMenu.addChild(titleText); // Create a single dynamic stats text block. var statsText = ""; statsText += "Total Money Earned: $" + gameState.totalMoneyEarned.toLocaleString() + "\n"; var achievedCount = achievements.filter(function(a) { return a.achieved; }).length; statsText += "Achievements: " + achievedCount + "/" + achievements.length + "\n"; statsText += "Prestige Count: " + gameState.prestigeCount + "\n"; var timePlayed = Math.floor((Date.now() - gameState.startTime) / 1000); statsText += "Time Played: " + timePlayed + " sec\n"; statsText += "Ore Taps: " + gameState.tapCount + "\n"; statsText += "Miner Hits: " + gameState.minerHitCount + "\n"; var fullyUpgraded = 0; for (var key in oreUpgrades) { oreUpgrades[key].forEach(function(upg) { if (upg.level >= upg.maxLevel) { fullyUpgraded++; } }); } statsText += "Fully Upgraded Ore Upgrades: " + fullyUpgraded + "\n"; statsTextObj = new Text2(statsText, { size: 40, fill: 0x000000, stroke: 0xFFFFFF, strokeThickness: 4, fontWeight: "bold", align: "center" }); statsTextObj.anchor.set(0.5); statsTextObj.x = menuBg.x; statsTextObj.y = menuBg.y; upgradeMenu.addChild(statsTextObj); var backBtn = LK.getAsset('cancelButton', { anchorX: 0.5, anchorY: 0.5 }); backBtn.x = menuBg.x + 700; backBtn.y = menuBg.y - 1000; backBtn.down = function () { createMainUpgradeMenu(); }; upgradeMenu.addChild(backBtn); } /**** * PRESTIGE MENU (unchanged) ****/ function createPrestigeMenu() { upgradeMenu.removeChildren(); var menuBg = LK.getAsset('rectangle', { width: 1800, height: 2200, color: 0x444444, anchorX: 0.5, anchorY: 0.5 }); menuBg.alpha = 0.9; menuBg.x = 2048 / 2; menuBg.y = 2732 / 2 + 50; upgradeMenu.addChild(menuBg); var titleText = new Text2("Prestige Upgrades", { size: 60, fill: 0xFFFFFF, stroke: 0x000000, strokeThickness: 4, align: "center", fontWeight: "bold" }); titleText.anchor.set(0.5); titleText.x = menuBg.x; titleText.y = menuBg.y - 1000; upgradeMenu.addChild(titleText); var startY = menuBg.y - 800, colSpacing = 400; for (var i = 0; i < prestigeUpgrades.length; i++) { var col = i % 2, row = Math.floor(i / 2); var btn = LK.getAsset('buy_button', { anchorX: 0.5, anchorY: 0.5 }); btn.x = menuBg.x + (col === 0 ? -colSpacing : colSpacing); btn.y = startY + row * 250; upgradeMenu.addChild(btn); var displayName = prestigeUpgrades[i].name; var txt = new Text2(displayName + "\nCost: " + prestigeUpgrades[i].cost + " Shards", { size: 45, fill: 0x000000, stroke: 0xFFFFFF, strokeThickness: 4, align: 'center', fontWeight: 'bold' }); txt.anchor.set(0.5); txt.x = btn.x; txt.y = btn.y; upgradeMenu.addChild(txt); btn.down = function (upg, btn) { return function (event) { event.stopPropagation && event.stopPropagation(); showUpgradeModal(upg, btn, function (confirmed) { if (confirmed && canPurchaseUpgrade(prestigeUpgrades, upg)) { gameState.prestigeCurrency -= upg.cost; upg.purchased = true; upg.action(); updateUI(); createPrestigeMenu(); } }); }; }(prestigeUpgrades[i], btn); } var backBtn = LK.getAsset('cancelButton', { anchorX: 0.5, anchorY: 0.5 }); backBtn.x = menuBg.x + 700; backBtn.y = menuBg.y - 1000; backBtn.down = function () { createMainUpgradeMenu(); }; upgradeMenu.addChild(backBtn); } /**** * GAME PAUSE FUNCTION (for Quantum Selection) ****/ game.pauseForQuantumSelection = function () { quantumSelectionActive = true; quantumSelectTimer = 0; }; /**** * START GAME ****/ function startGame() { currentBackground = LK.getAsset('background', { anchorX: 0.5, anchorY: 0.5 }); currentBackground.x = 2048 / 2; currentBackground.y = 2732 / 2; currentBackground.zIndex = -100; game.addChildAt(currentBackground, 0); miner = new Miner(); miner.x = 2048 / 2; miner.y = 2732 / 2; game.addChild(miner); initialSpawn(); updateUI(); } startGame(); ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Please fix the bug: 'getValidClusterCenter is not defined' in or related to this line: 'var center = getValidClusterCenter();' Line Number: 81
User prompt
Please fix the bug: 'getValidClusterCenter is not defined' in or related to this line: 'var center = getValidClusterCenter();' Line Number: 81
Code edit (2 edits merged)
Please save this source code
User prompt
Please fix the bug: 'getValidClusterCenter is not defined' in or related to this line: 'var center = getValidClusterCenter();' Line Number: 81
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'getValidClusterCenter is not defined' in or related to this line: 'var center = getValidClusterCenter();' Line Number: 65
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'getValidClusterCenter is not defined' in or related to this line: 'var center = getValidClusterCenter();' Line Number: 65
User prompt
Please fix the bug: 'getValidClusterCenter is not defined' in or related to this line: 'var center = getValidClusterCenter();' Line Number: 65
Code edit (2 edits merged)
Please save this source code
User prompt
Please fix the bug: 'Miner is not defined' in or related to this line: 'miner = new Miner();' Line Number: 1763
Code edit (1 edits merged)
Please save this source code
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ /**** * CLASSES ****/ /** Cluster – spawns multiple ore objects. **/ var Cluster = Container.expand(function (type) { var self = Container.call(this); self.type = type; self.oreList = []; self.zIndex = 0; // Use the helper to generate a valid spawn position (avoiding UI areas) var center = getValidClusterCenter(); self.x = center.x; self.y = center.y; var cc = gameState.clusterConfig; var count = randomInt(cc.min, cc.max); for (var i = 0; i < count; i++) { var ore = new Ore(type, self); ore.x = (Math.random() - 0.5) * 120; ore.y = (Math.random() - 0.5) * 120; self.oreList.push(ore); self.addChild(ore); } // Modified: Increment ore mined for each ore (not once per cluster) self.notifyOreDestroyed = function (ore) { var idx = self.oreList.indexOf(ore); if (idx >= 0) { self.oreList.splice(idx, 1); } ore.destroy(); // Increment individual ore mined stat here. gameState.oreMined[type] = (gameState.oreMined[type] || 0) + 1; if (self.oreList.length === 0) { if (self.parent) { self.parent.removeChild(self); } var cidx = clusters.indexOf(self); if (cidx >= 0) { clusters.splice(cidx, 1); } gameState.clusterCount[type]--; var finalDelay = gameState.respawnTime; if (type === 'coal') { finalDelay *= 2; } LK.setTimeout(function () { maybeSpawnCluster(type); }, finalDelay); } }; return self; }); /** Drone – moves and zaps ores. **/ var Drone = Container.expand(function () { var self = Container.call(this); self.droneSprite = LK.getAsset('drone_asset', { anchorX: 0.5, anchorY: 0.5 }); self.addChild(self.droneSprite); self.AOE_RANGE = 150; self.droneDamage = 2; self.COOLDOWN_MAX = 60; self.cooldown = 0; var SPEED = 8, MIN_X = 50, MAX_X = 2000, MIN_Y = 50, MAX_Y = 2682; self.vx = Math.random() < 0.5 ? SPEED : -SPEED; self.vy = Math.random() < 0.5 ? SPEED : -SPEED; self.updateDrone = function () { self.x += self.vx; self.y += self.vy; if (self.x < MIN_X || self.x > MAX_X) { self.vx = -self.vx; } if (self.y < MIN_Y || self.y > MAX_Y) { self.vy = -self.vy; } if (Math.random() < 0.01) { self.vx += (Math.random() - 0.5) * 2; self.vy += (Math.random() - 0.5) * 2; var speed = Math.sqrt(self.vx * self.vx + self.vy * self.vy); if (speed > SPEED) { self.vx = self.vx / speed * SPEED; self.vy = self.vy / speed * SPEED; } } self.droneSprite.rotation += 0.1; if (self.cooldown > 0) { self.cooldown--; } else { self.tryZap(); } }; self.tryZap = function () { var hitSomething = false; clusters.forEach(function (cluster) { cluster.oreList.forEach(function (ore) { if (ore.health > 0) { var oreGlobalX = cluster.x + ore.x, oreGlobalY = cluster.y + ore.y; var dx = self.x - oreGlobalX, dy = self.y - oreGlobalY; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < self.AOE_RANGE) { var damage = self.droneDamage; var actualDamage = Math.min(damage, ore.health); var fraction = actualDamage / ore.maxHealth; var reward = Math.round(fraction * ore.getValue()); if (ore.awardedMoney + reward > ore.getValue()) { reward = ore.getValue() - ore.awardedMoney; } ore.awardedMoney += reward; gameState.money += reward; gameState.totalMoneyEarned += reward; updateUI(); ore.health -= actualDamage; hitSomething = true; spawnDroneAOE(ore); if (ore.health <= 0) { ore.cluster.notifyOreDestroyed(ore); spawnMiningParticles(ore, 5); } else { spawnMiningParticles(ore, 2); } // Show floating text for drone hit (red) showFloatingText(reward, 0xFF0000); } } }); }); if (hitSomething) { LK.getSound('drone_shot').play(); self.cooldown = self.COOLDOWN_MAX; } }; return self; }); /** Miner – moves toward and mines the nearest ore. **/ var Miner = Container.expand(function () { var self = Container.call(this); self.attachAsset('miner', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 5; self.currentTarget = null; self.miningRange = 25; self.miningCooldown = 0; self.miningRate = 60; self.miningDamage = 1; self.originalMiningRate = self.miningRate; self.originalMiningDamage = self.miningDamage; self.speedBoostMultiplier = 1; self.speedBoostTimer = 0; self.soulEmberStacks = 0; self.quantumPathActive = false; self.quantumPath = []; self.quantumShardValueBonus = false; self.hyperMiningActive = false; self.hyperMiningTimer = 0; // (Other methods remain unchanged.) // Update method (modified to account for pause and special effects) self.update = function () { if (self.hyperMiningActive) { self.hyperMiningTimer--; if (self.hyperMiningTimer <= 0) { self.miningDamage = self.originalMiningDamage; self.miningRate = self.originalMiningRate; self.hyperMiningActive = false; } } if (self.speedBoostTimer > 0) { self.speedBoostTimer--; if (self.speedBoostTimer <= 0) { self.speedBoostMultiplier = 1; } } self.findNewTarget(); if (self.currentTarget && self.currentTarget.parent) { var tx = self.currentTarget.parent.x + self.currentTarget.x, ty = self.currentTarget.parent.y + self.currentTarget.y; var dx = tx - self.x, dy = ty - self.y, dist = Math.sqrt(dx * dx + dy * dy); var finalSpeed = self.speed * self.speedBoostMultiplier; if (dist > self.miningRange) { self.x += dx / dist * finalSpeed; self.y += dy / dist * finalSpeed; } else { self.mineOre(self.currentTarget); } } else { self.currentTarget = null; // Ensure currentTarget is reset if undefined if (typeof LK.time !== 'undefined') { self.y += Math.sin(LK.time.elapsed / 250) * 0.5; } } }; self.findNewTarget = function () { if (self.quantumPathActive && self.quantumPath.length > 0) { self.currentTarget = self.quantumPath[0]; if (!self.currentTarget || self.currentTarget.health <= 0) { self.quantumPath.shift(); if (self.quantumPath.length === 0) { self.quantumShardValueBonus = false; self.quantumPathActive = false; self.currentTarget = null; } return; } return; } var validOre = []; clusters.forEach(function (c) { c.oreList.forEach(function (ore) { if (ore.health > 0 && (ore.tier <= gameState.currentTier || ore.type === "chronostone" || ore.type === "soulember" || ore.type === "quantumshard")) { validOre.push(ore); } }); }); if (validOre.length === 0) { self.currentTarget = null; return; } self.currentTarget = validOre.sort(function (a, b) { var aX = a.parent.x + a.x, aY = a.parent.y + a.y; var bX = b.parent.x + b.x, bY = b.parent.y + b.y; return Math.hypot(aX - self.x, aY - self.y) - Math.hypot(bX - self.x, bY - self.y); })[0]; }; // Modified mineOre to account for soul ember boost. self.mineOre = function (ore) { if (self.miningCooldown > 0) { self.miningCooldown--; return; } var damageDealt = self.miningDamage * gameState.pickaxeLevel * (gameState.pickaxeBaseMultiplier || 1); // If Soul Ember boost is active, double the damage and reward. if (soulEmberActive && soulEmberBoostCount > 0) { damageDealt *= 2; } var actualDamage = Math.min(damageDealt, ore.health); var fraction = actualDamage / ore.maxHealth; var rewardMultiplier = 1; if (soulEmberActive && soulEmberBoostCount > 0) { rewardMultiplier = 2; } var reward = Math.round(fraction * ore.getValue() * rewardMultiplier); if (ore.awardedMoney + reward > ore.getValue()) { reward = ore.getValue() - ore.awardedMoney; } ore.awardedMoney += reward; gameState.money += reward; gameState.totalMoneyEarned += reward; gameState.minerHitCount++; updateUI(); var mineSound = LK.getSound('mine_' + ore.type); if (mineSound) { mineSound.play(); } ore.health -= actualDamage; self.miningCooldown = self.miningRate; if (ore.health <= 0) { spawnMiningParticles(ore, 5); var destroySound = LK.getSound('ore_destroy_' + ore.type); if (destroySound) { destroySound.play(); } if (ore.type === "explosive" && ore.explode) { ore.explode(); // If explosive ore and prestige >=12 and no meteor shower active, trigger meteor shower. if (gameState.prestigeCount >= 12 && !meteorShowerActive) { triggerMeteorShowerEffect(); } } ore.cluster.notifyOreDestroyed(ore); // If Soul Ember boost is active, decrease its counter and show boosted floating text. if (soulEmberActive && soulEmberBoostCount > 0) { soulEmberBoostCount--; showFloatingText(reward, 0xFFD700); // Gold, bold floating text if (soulEmberBoostCount <= 0) { soulEmberActive = false; if (soulEmberOverlay && soulEmberOverlay.parent) { soulEmberOverlay.parent.removeChild(soulEmberOverlay); soulEmberOverlay.destroy(); soulEmberOverlay = null; } soulEmberBannerShown = false; } } else { // Normal floating text for miner hit (green) showFloatingText(reward, 0x00FF00); } // Trigger special ore effects if applicable. if (ore.type === "chronostone" && !chronostoneActive) { triggerChronostoneEffect(); } if (ore.type === "soulember" && !soulEmberActive) { triggerSoulEmberEffect(); } if (ore.type === "quantumshard" && !quantumShardActive) { triggerQuantumShardEffect(); } } else { spawnMiningParticles(ore, 2); showFloatingText(reward, 0x00FF00); } }; self.applyChronostoneBoost = function () { self.speedBoostMultiplier *= 3; self.speedBoostTimer = 30 * 60; // 30 sec boost }; self.applySoulEmberBoost = function () { // (Deprecated – now handled in triggerSoulEmberEffect) }; self.triggerQuantumShardMode = function () { self.quantumShardValueBonus = true; self.quantumPathActive = true; self.quantumPath = []; game.pauseForQuantumSelection(); }; return self; }); /** MiniMiner – spawned by Quantum Shard effect **/ var MiniMiner = Container.expand(function (parentMiner) { var self = Container.call(this); // Use the miner asset but scaled down. self.attachAsset('miner', { anchorX: 0.5, anchorY: 0.5, scale: 0.5 }); self.speed = parentMiner.speed * 1.2; self.miningDamage = parentMiner.miningDamage; self.miningRate = parentMiner.miningRate; self.currentTarget = null; self.update = function () { // Simple movement toward a target ore. if (self.currentTarget) { var tx = self.currentTarget.parent.x + self.currentTarget.x, ty = self.currentTarget.parent.y + self.currentTarget.y; var dx = tx - self.x, dy = ty - self.y, dist = Math.sqrt(dx * dx + dy * dy); if (dist > 25) { self.x += dx / dist * self.speed; self.y += dy / dist * self.speed; } else { // Attack the ore and show pink, bold floating text offset lower. self.currentTarget.health -= self.miningDamage; // Offset the floating text (e.g., add extra Y offset) showFloatingText(Math.round(self.miningDamage), 0xFF69B4); if (self.currentTarget.health <= 0) { self.currentTarget.cluster.notifyOreDestroyed(self.currentTarget); self.currentTarget = null; } } } else { // Find an available ore. var validOre = []; clusters.forEach(function (c) { c.oreList.forEach(function (ore) { if (ore.health > 0) { validOre.push(ore); } }); }); if (validOre.length > 0) { self.currentTarget = validOre[Math.floor(Math.random() * validOre.length)]; } } }; return self; }); /** Ore – represents a single ore. **/ var Ore = Container.expand(function (type, cluster) { var self = Container.call(this); self.type = type; self.cluster = cluster; self.zIndex = 0; var typeList = ['coal', 'iron', 'gold', 'diamond', 'sapphire', 'emerald', 'ruby']; if (typeList.indexOf(type) >= 0) { self.tier = typeList.indexOf(type) + 1; } else { self.tier = 999; } self.baseValue = oreData[type].baseValue; self.maxHealth = oreData[type].baseHealth; self.health = self.maxHealth; self.attachAsset(oreData[type].assetId, { anchorX: 0.5, anchorY: 0.5 }); // Health bar using the new health_bar asset. self.healthBar = LK.getAsset('health_bar', { width: 120, height: 20, color: 0x00FF00, anchorX: 0.5, anchorY: 0.5 }); self.healthBar.x = 0; self.healthBar.y = -70; self.addChild(self.healthBar); self.awardedMoney = 0; self.lastTapTime = 0; self.interactive = true; self.buttonMode = true; self.down = function () { var currentTime = typeof LK.time !== 'undefined' ? LK.time.elapsed : Date.now(); if (currentTime - self.lastTapTime < 1) { return; } self.lastTapTime = currentTime; var hitSound = LK.getSound('mine_' + self.type); if (hitSound) { hitSound.play(); } var damage = gameState.tapDamage; var actualDamage = Math.min(damage, self.health); var fraction = actualDamage / self.maxHealth; var reward = Math.round(fraction * self.getValue()); if (self.awardedMoney + reward > self.getValue()) { reward = self.getValue() - self.awardedMoney; } self.awardedMoney += reward; gameState.money += reward; gameState.totalMoneyEarned += reward; gameState.tapCount++; updateUI(); self.health -= actualDamage; spawnMiningParticles(self, 2); // Check for special ore triggers upon destruction. if (self.health <= 0) { var destroySound = LK.getSound('ore_destroy_' + self.type); if (destroySound) { destroySound.play(); } // For special ores, trigger their effects if not active. if (self.type === "chronostone" && !chronostoneActive) { triggerChronostoneEffect(); } if (self.type === "soulember" && !soulEmberActive) { triggerSoulEmberEffect(); } if (self.type === "quantumshard" && !quantumShardActive) { triggerQuantumShardEffect(); } self.cluster.notifyOreDestroyed(self); // Show floating text for ore tap (blue) showFloatingText(reward, 0x0000FF); } }; // If the ore is one of the special types, add a pulsing glow. if (["chronostone", "soulember", "quantumshard"].indexOf(type) >= 0) { var _pulseGlow2 = function _pulseGlow() { tween(glow, { alpha: 1 }, { duration: 1000, onFinish: function onFinish() { tween(glow, { alpha: 0.5 }, { duration: 1000, onFinish: _pulseGlow2 }); } }); }; var glow = LK.getAsset('glowing_line_asset', { anchorX: 0.5, anchorY: 0.5 }); glow.alpha = 0.5; self.addChildAt(glow, 0); _pulseGlow2(); } if (type === "explosive") { self.explode = function () { var explosionRadius = 100; clusters.forEach(function (cluster) { cluster.oreList.forEach(function (otherOre) { if (otherOre !== self && otherOre.health > 0) { var oreGlobalX = cluster.x + otherOre.x, oreGlobalY = cluster.y + otherOre.y; var dx = self.parent.x + self.x - oreGlobalX, dy = self.parent.y + self.y - oreGlobalY; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < explosionRadius) { otherOre.health -= 50; if (otherOre.health <= 0) { var baseValue = otherOre.getValue(); gameState.money += baseValue; updateUI(); otherOre.cluster.notifyOreDestroyed(otherOre); spawnMiningParticles(otherOre, 5); } else { spawnMiningParticles(otherOre, 2); } } } }); }); screenShake(500, 10); }; } self.getValue = function () { var val = self.baseValue * gameState.oreMultipliers[self.type]; return Math.round(val / 2) * 2; }; return self; }); /** SingleOre – container for special ores that spawn individually **/ var SingleOre = Container.expand(function (type) { var self = Container.call(this); self.type = type; // Create the ore; pass this container as its cluster. var ore = new Ore(type, self); ore.x = 0; ore.y = 0; self.addChild(ore); // Custom notify function: when the single ore is destroyed, remove the container and clear the special ore reference. self.notifyOreDestroyed = function (ore) { ore.destroy(); gameState.oreMined[type] = (gameState.oreMined[type] || 0) + 1; if (self.parent) { self.parent.removeChild(self); } specialOres[type] = null; }; return self; }); /**** * Initialize Game ****/ /**** * INITIALIZE GAME ****/ var game = new LK.Game({ backgroundColor: 0x1a1a1a }); /**** * Game Code ****/ // Helper function to get a valid cluster center position function getValidClusterCenter() { // Define the UI boundaries or any restricted areas var uiMargin = 200; var minX = uiMargin; var maxX = 2048 - uiMargin; var minY = uiMargin; var maxY = 2732 - uiMargin; // Generate a random position within the valid area var x = randomInt(minX, maxX); var y = randomInt(minY, maxY); return { x: x, y: y }; } /**** * GLOBAL VARIABLES & SPECIAL EFFECT FLAGS ****/ /**** * PLUGINS ****/ /**** * GAME-STATE & STATS ****/ var statsTextObj = null; // will store the Text2 object for the stats // Special ore effect flags and timers (assuming 60 FPS) var chronostoneActive = false; var chronostoneTimer = 0; // in frames (30 sec = 30*60) var chronostoneOverlay = null; var chronostoneTimerText = null; var chronostoneBannerShown = false; var soulEmberActive = false; var soulEmberOverlay = null; var soulEmberBannerShown = false; var soulEmberBoostCount = 0; // lasts for 10 ore mines var quantumShardActive = false; var quantumShardTimer = 0; // 10 sec effect var quantumShardOverlay = null; var quantumShardBannerShown = false; var miniMiners = []; // array to hold mini miner instances var meteorShowerActive = false; var meteorShowerBannerShown = false; // For special ores that spawn singularly (instead of in clusters) var specialOres = { chronostone: null, soulember: null, quantumshard: null }; var gameState = { money: 0, pickaxeLevel: 1, pickaxeBaseMultiplier: 1, droneLevel: 0, currentTier: 1, oreMultipliers: { coal: 1, iron: 1, gold: 1, diamond: 1, sapphire: 1, emerald: 1, ruby: 1, chronostone: 1, soulember: 1, quantumshard: 1 }, respawnTime: 3000, maxClustersPerType: 3, clusterCount: { coal: 0, iron: 0, gold: 0, diamond: 0, sapphire: 0, emerald: 0, ruby: 0, chronostone: 0, soulember: 0, quantumshard: 0 }, clusterConfigLevels: [{ min: 2, max: 3 }, { min: 3, max: 4 }, { min: 4, max: 5 }, { min: 5, max: 6 }, { min: 6, max: 7 }, { min: 6, max: 8 }], clusterUpgradeTier: 0, get clusterConfig() { return this.clusterConfigLevels[this.clusterUpgradeTier] || { min: 2, max: 3 }; }, prestigeCount: 0, prestigeCurrency: 0, tapDamage: 1, totalMoneyEarned: 0, tapCount: 0, minerHitCount: 0, startTime: Date.now(), oreMined: { coal: 0, iron: 0, gold: 0, diamond: 0, sapphire: 0, emerald: 0, ruby: 0, chronostone: 0, soulember: 0, quantumshard: 0 } }; /**** * ACHIEVEMENTS ****/ var achievements = [{ id: 'first_mine', name: 'First Mine', description: 'Mine your first ore', achieved: false, condition: function condition() { return gameState.money > 0; } }, { id: 'rich_miner', name: 'Rich Miner', description: 'Earn 1 Billion money', achieved: false, condition: function condition() { return gameState.money >= 1e9; } }, { id: 'coal_miner', name: 'Coal Miner', description: 'Mine 50 coal ores', achieved: false, target: 50, condition: function condition() { return gameState.oreMined.coal >= 50; } }]; /**** * ORE DATA (Even values) ****/ var oreData = { coal: { baseValue: 5, baseHealth: 10, assetId: 'coal_ore' }, iron: { baseValue: 500, baseHealth: 100, assetId: 'iron_ore' }, gold: { baseValue: 10000, baseHealth: 500, assetId: 'gold_ore' }, diamond: { baseValue: 25000, baseHealth: 1000, assetId: 'diamond_ore' }, sapphire: { baseValue: 100000, baseHealth: 2000, assetId: 'sapphire_ore' }, emerald: { baseValue: 500000, baseHealth: 5000, assetId: 'emerald_ore' }, ruby: { baseValue: 1000000, baseHealth: 10000, assetId: 'ruby_ore' }, chronostone: { baseValue: 2000000, baseHealth: 2000, assetId: 'chronostone_ore', color: 0xc997d8 }, soulember: { baseValue: 5000000, baseHealth: 5000, assetId: 'soulember_ore', color: 0xdef3e5 }, quantumshard: { baseValue: 10000000, baseHealth: 10000, assetId: 'quantumshard_ore', color: 0xa1bb12 } }; function hideUpgradeDesc() {/* Placeholder */} function randomInt(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; } function spawnMiningParticles(ore, num) { for (var i = 0; i < num; i++) { var p = LK.getAsset('mining_particle', { anchorX: 0.5, anchorY: 0.5 }); if (ore.parent) { p.x = ore.parent.x + ore.x; p.y = ore.parent.y + ore.y; } else { p.x = ore.x; p.y = ore.y; } if (["chronostone", "soulember", "quantumshard"].indexOf(ore.type) >= 0) { p.tint = oreData[ore.type].color || 0xffffff; } p.vx = (Math.random() - 0.5) * 10; p.vy = (Math.random() - 0.5) * 10; p.alpha = 1; p.zIndex = -1; tween(p, { alpha: 0, y: p.y - 50 }, { duration: 1000, onFinish: function onFinish() { p.destroy(); } }); game.addChild(p); } } function interpolateColor(c1, c2, f) { var r1 = c1 >> 16 & 0xFF, g1 = c1 >> 8 & 0xFF, b1 = c1 & 0xFF; var r2 = c2 >> 16 & 0xFF, g2 = c2 >> 8 & 0xFF, b2 = c2 & 0xFF; var r = Math.round(r1 + f * (r2 - r1)), g = Math.round(g1 + f * (g2 - g1)), b = Math.round(b1 + f * (b2 - b1)); return r << 16 | g << 8 | b; } function screenShake(duration, magnitude) { var originalX = game.x, originalY = game.y, shakeInterval = 50, elapsed = 0; var shake = setInterval(function () { elapsed += shakeInterval; game.x = originalX + (Math.random() - 0.5) * magnitude; game.y = originalY + (Math.random() - 0.5) * magnitude; if (elapsed >= duration) { clearInterval(shake); game.x = originalX; game.y = originalY; } }, shakeInterval); } function spawnDroneAOE(ore) { var effect = LK.getAsset('drone_aoe_effect', { anchorX: 0.5, anchorY: 0.5 }); if (ore.parent) { effect.x = ore.parent.x + ore.x; effect.y = ore.parent.y + ore.y; } else { effect.x = ore.x; effect.y = ore.y; } effect.alpha = 1; effect.zIndex = 1; game.addChild(effect); tween(effect, { alpha: 0 }, { duration: 500, onFinish: function onFinish() { effect.destroy(); } }); } /**** * SPECIAL EFFECT FUNCTIONS ****/ // Helper: Display an event banner (bold, black text with outline) at the top. function showEventBanner(text) { var banner = new Text2(text, { size: 60, fill: 0x000000, stroke: 0xFFFFFF, strokeThickness: 4, fontWeight: 'bold', align: 'center' }); banner.anchor.set(0.5); banner.x = 2048 / 2; banner.y = 200; game.addChild(banner); tween(banner, { alpha: 0, y: banner.y - 50 }, { duration: 3000, onFinish: function onFinish() { banner.destroy(); } }); } // Chronostone effect: speed boost for 30 seconds with overlay and countdown. function triggerChronostoneEffect() { chronostoneActive = true; chronostoneTimer = 30 * 60; // 30 seconds (in frames) if (!chronostoneBannerShown) { showEventBanner("Chronostone Speed Boost"); chronostoneBannerShown = true; } if (!chronostoneOverlay) { chronostoneOverlay = LK.getAsset('chronostone_overlay', { anchorX: 0.5, anchorY: 0.5, alpha: 0.5 }); chronostoneOverlay.x = 2048 / 2; chronostoneOverlay.y = 2732 / 2; game.addChild(chronostoneOverlay); } if (!chronostoneTimerText) { chronostoneTimerText = new Text2("30", { size: 50, fill: 0x000000, stroke: 0xFFFFFF, strokeThickness: 4, fontWeight: 'bold' }); chronostoneTimerText.x = 50; chronostoneTimerText.y = 50; game.addChild(chronostoneTimerText); } if (miner) { miner.speedBoostMultiplier *= 2; // apply boost multiplier miner.speedBoostTimer = chronostoneTimer; } } // Soul Ember effect: boost ore value and miner damage for 10 ore mines with red overlay and money drain display. function triggerSoulEmberEffect() { soulEmberActive = true; if (!soulEmberBannerShown) { showEventBanner("Soul Ember +Dmg/+$"); soulEmberBannerShown = true; } if (!soulEmberOverlay) { soulEmberOverlay = LK.getAsset('soulember_overlay', { anchorX: 0.5, anchorY: 0.5, alpha: 0.5 }); soulEmberOverlay.x = 2048 / 2; soulEmberOverlay.y = 2732 / 2; game.addChild(soulEmberOverlay); } // Deduct 10% of money and show floating text for the deduction. var drain = gameState.money * 0.10; gameState.money -= drain; updateUI(); showFloatingText("-$" + Math.floor(drain).toLocaleString(), 0xFF0000); soulEmberBoostCount = 10; // boost lasts for 10 ore mines // Increase miner damage multiplier (for example purposes, increase by 50%) gameState.pickaxeBaseMultiplier *= 1.5; } // Quantum Shard effect: split the miner into 5 mini miners for 10 seconds with blue overlay. function triggerQuantumShardEffect() { quantumShardActive = true; quantumShardTimer = 10 * 60; // 10 seconds if (!quantumShardBannerShown) { showEventBanner("Quantum Split Miner Split"); quantumShardBannerShown = true; } if (!quantumShardOverlay) { quantumShardOverlay = LK.getAsset('quantumshard_overlay', { anchorX: 0.5, anchorY: 0.5, alpha: 0.5 }); quantumShardOverlay.x = 2048 / 2; quantumShardOverlay.y = 2732 / 2; game.addChild(quantumShardOverlay); } // Spawn 5 mini miners around the main miner. for (var i = 0; i < 5; i++) { var mini = new MiniMiner(miner); mini.x = miner.x + (Math.random() - 0.5) * 100; mini.y = miner.y + (Math.random() - 0.5) * 100; miniMiners.push(mini); game.addChild(mini); } } // Meteor Shower effect (for Explosive Ore after Prestige 12): spawn meteors that damage ores. function triggerMeteorShowerEffect() { meteorShowerActive = true; if (!meteorShowerBannerShown) { showEventBanner("Meteor Shower"); meteorShowerBannerShown = true; } var numMeteors = Math.floor(Math.random() * 2) + 3; // 3 or 4 meteors for (var i = 0; i < numMeteors; i++) { spawnMeteor(); } LK.setTimeout(function () { meteorShowerActive = false; meteorShowerBannerShown = false; }, 5000); } function spawnMeteor() { var meteor = LK.getAsset('meteor_shower', { anchorX: 0.5, anchorY: 0.5 }); meteor.x = 100 + Math.random() * (2048 - 200); meteor.y = -100; // start above screen game.addChild(meteor); var target = getValidClusterCenter(); tween(meteor, { x: target.x, y: target.y }, { duration: 1000, onFinish: function onFinish() { var aoe = LK.getAsset('meteor_aoe', { anchorX: 0.5, anchorY: 0.5, alpha: 0.7 }); aoe.x = target.x; aoe.y = target.y; game.addChild(aoe); // Damage ores within 50px in each direction (100x100 area) clusters.forEach(function (cluster) { cluster.oreList.forEach(function (ore) { var oreGlobalX = cluster.x + ore.x, oreGlobalY = cluster.y + ore.y; if (Math.abs(oreGlobalX - target.x) < 50 && Math.abs(oreGlobalY - target.y) < 50) { var damage = 100; // high damage value ore.health -= damage; showFloatingText("Meteor: " + damage, 0xFFFFFF); if (ore.health <= 0) { ore.cluster.notifyOreDestroyed(ore); } } }); }); tween(aoe, { alpha: 0 }, { duration: 1000, onFinish: function onFinish() { aoe.destroy(); } }); meteor.destroy(); } }); } /**** * UI HELPER: Floating Text ****/ // Colors: green for miner hits (0x00FF00), blue for ore taps (0x0000FF), red for drone hits (0xFF0000) // (For mini miners, we’ll use pink (0xFF69B4) and offset lower.) function showFloatingText(amount, color) { var txt = new Text2("+" + amount, { size: 40, fill: color, stroke: color, strokeThickness: 4, align: 'center', fontWeight: 'bold' }); // Adjust position based on type of hit: var offsetX = (Math.random() - 0.5) * 50; var offsetY = (Math.random() - 0.5) * 50; if (color === 0xFF0000) { offsetX += 300; } else if (color === 0x0000FF) { offsetX -= 300; } else if (color === 0xFF69B4) { // for mini miners, lower the text offsetY += 50; } txt.x = moneyDisplay.x + moneyDisplay.width / 2 + offsetX; txt.y = moneyDisplay.y + moneyDisplay.height + offsetY; game.addChild(txt); tween(txt, { alpha: 0, y: txt.y - 20 }, { duration: 1000, onFinish: function onFinish() { txt.destroy(); } }); } /**** * SPECIAL SPAWNING: Prevent special ores from spawning in clusters. ****/ function maybeSpawnCluster(type) { // For special ores, do not spawn clusters. if (type === "chronostone" || type === "soulember" || type === "quantumshard") { return; } var typeList = ['coal', 'iron', 'gold', 'diamond', 'sapphire', 'emerald', 'ruby']; if (typeList.indexOf(type) >= 0) { var tIndex = typeList.indexOf(type) + 1; if (tIndex > gameState.currentTier) { return; } } if (gameState.clusterCount[type] >= gameState.maxClustersPerType) { return; } var cluster = new Cluster(type); game.addChild(cluster); clusters.push(cluster); gameState.clusterCount[type]++; } // For special ores, spawn them singularly. function maybeSpawnSpecialOres() { var specialTypes = ['chronostone', 'soulember', 'quantumshard']; specialTypes.forEach(function (type) { if (!specialOres[type]) { if (type === 'chronostone' && gameState.prestigeCount >= 3) { spawnSingleOre(type); } if (type === 'soulember' && gameState.prestigeCount >= 5) { spawnSingleOre(type); } if (type === 'quantumshard' && gameState.prestigeCount >= 8) { spawnSingleOre(type); } } }); } function spawnSingleOre(type) { var singleOre = new SingleOre(type); var pos = getValidClusterCenter(); singleOre.x = pos.x; singleOre.y = pos.y; game.addChild(singleOre); specialOres[type] = singleOre; } /**** * PRESTIGE & BACKGROUND TRANSITION ****/ function getPrestigeRequirement() { return 1e9 * Math.pow(2, gameState.prestigeCount); } function canPrestige() { return gameState.money >= getPrestigeRequirement(); } function calculatePrestigeShards() { return 1; } /** * doPrestige: * - Removes all clusters and drones. * - Resets upgrades. * - Resets miner swing speed to its base value. * - Pauses game during background transition. * - Initiates background transition. Once complete, resumes gameplay. */ function doPrestige() { for (var i = clusters.length - 1; i >= 0; i--) { var c = clusters[i]; c.removeChildren(); if (c.parent) { c.parent.removeChild(c); } clusters.splice(i, 1); } droneObjects.forEach(function (d) { if (d.parent) { d.parent.removeChild(d); } }); droneObjects = []; droneSprites.forEach(function (ds) { if (ds.parent) { ds.parent.removeChild(ds); } }); droneSprites = []; var shards = calculatePrestigeShards(); gameState.prestigeCurrency += shards; gameState.prestigeCount++; gameState.money = 0; gameState.currentTier = 1; for (var key in gameState.clusterCount) { gameState.clusterCount[key] = 0; } resetUpgrades(); gameState.droneLevel = 0; if (miner) { miner.miningRate = miner.originalMiningRate; } gamePaused = true; handleBackgroundTransition(); updateUI(); } function resetUpgrades() { gameState.oreMultipliers = { coal: 1, iron: 1, gold: 1, diamond: 1, sapphire: 1, emerald: 1, ruby: 1, chronostone: 1, soulember: 1, quantumshard: 1 }; gameState.pickaxeLevel = 1; gameState.pickaxeBaseMultiplier = 1; gameState.tapDamage = 1; gameState.respawnTime = 3000; gameState.clusterUpgradeTier = 0; for (var key in oreUpgrades) { oreUpgrades[key].forEach(function (upg) { if (upg.initCost === undefined) { upg.initCost = upg.cost; } upg.cost = upg.initCost; upg.level = 0; upg.purchased = false; }); } generalUpgrades.forEach(function (upg) { if (upg.initCost === undefined) { upg.initCost = upg.cost; } upg.cost = upg.initCost; upg.level = 0; upg.purchased = false; }); droneUpgrades.forEach(function (upg) { if (upg.initCost === undefined) { upg.initCost = upg.cost; } upg.cost = upg.initCost; upg.level = 0; upg.purchased = false; }); } function handleBackgroundTransition() { var bgAssetId; if (gameState.prestigeCount >= 8) { bgAssetId = 'background_tier8'; } else if (gameState.prestigeCount >= 5) { bgAssetId = 'background_tier5'; } else if (gameState.prestigeCount >= 3) { bgAssetId = 'background_tier3'; } else { bgAssetId = 'background'; } // Remove any existing nextBackground from previous transitions. if (nextBackground && nextBackground.parent) { nextBackground.parent.removeChild(nextBackground); if (typeof nextBackground.destroy === "function") { nextBackground.destroy(); } } // Create the new background off–screen at the bottom. var newBg = LK.getAsset(bgAssetId, { anchorX: 0.5, anchorY: 0.5 }); newBg.x = 2048 / 2; newBg.y = 2732 + 2732 / 2; // Position offscreen (below) newBg.zIndex = -100; game.addChildAt(newBg, 0); nextBackground = newBg; // Use currentBackground as the old background; if not set, create one. var oldBg = currentBackground; if (!oldBg) { oldBg = LK.getAsset(bgAssetId, { anchorX: 0.5, anchorY: 0.5 }); oldBg.x = 2048 / 2; oldBg.y = 2732 / 2; oldBg.zIndex = -100; game.addChildAt(oldBg, 0); } var dur = 3000; // Animate the old background sliding upward (out of view). tween(oldBg, { y: -2732 / 2 }, { duration: dur, onFinish: function onFinish() { if (oldBg && oldBg.parent) { oldBg.parent.removeChild(oldBg); if (typeof oldBg.destroy === "function") { oldBg.destroy(); } } } }); // Animate the new background sliding in to center. tween(newBg, { y: 2732 / 2 }, { duration: dur, onFinish: function onFinish() { currentBackground = newBg; gamePaused = false; initialSpawn(); } }); } var clusters = []; var currentBackground = null; var nextBackground = null; var miner = null; var droneObjects = []; var droneSprites = []; var prestigeMainButton = null; var gamePaused = false; /**** * SPAWN FUNCTIONS ****/ function initialSpawn() { if (gamePaused) { return; } var allTypes = ['coal', 'iron', 'gold', 'diamond', 'sapphire', 'emerald', 'ruby']; allTypes.forEach(function (type, idx) { var t = idx + 1; if (t <= gameState.currentTier) { for (var i = 0; i < gameState.maxClustersPerType; i++) { maybeSpawnCluster(type); } } }); maybeSpawnSpecialOres(); } function updateDroneObjects() { while (droneObjects.length < gameState.droneLevel) { var d = new Drone(); d.x = 200 + Math.random() * (2048 - 400); d.y = 200 + Math.random() * (2732 - 400); droneObjects.push(d); game.addChild(d); } } function updateDroneSprites() { while (droneSprites.length < gameState.droneLevel) { var drone = LK.getAsset('drone_asset', { anchorX: 0.5, anchorY: 0.5 }); drone.x = 100 + droneSprites.length * 90; drone.y = 200; droneSprites.push(drone); game.addChild(drone); } } /**** * UPGRADE DATA ****/ // (Upgrade data remains unchanged) var oreUpgrades = { coal: [{ id: 'double_coal', name: 'Double Coal Value', cost: 100, multi: true, level: 0, maxLevel: 20, effect: 'Doubles Coal Value each purchase', action: function action() { this.level++; gameState.oreMultipliers.coal *= 2; this.cost *= 2; } }], iron: [{ id: 'unlock_iron', name: 'Unlock Iron Mining', cost: 7000, effect: 'Allows iron ore clusters to spawn', purchased: false, action: function action() { if (gameState.currentTier < 2) { gameState.currentTier = 2; } for (var i = 0; i < gameState.maxClustersPerType; i++) { maybeSpawnCluster('iron'); } } }, { id: 'double_iron', name: 'Double Iron Value', cost: 1000, multi: true, level: 0, maxLevel: 20, effect: 'Doubles Iron Value each purchase', action: function action() { this.level++; gameState.oreMultipliers.iron *= 2; this.cost *= 2; } }], gold: [{ id: 'unlock_gold', name: 'Unlock Gold Mining', cost: 70000, effect: 'Allows gold ore clusters to spawn', purchased: false, action: function action() { if (gameState.currentTier < 3) { gameState.currentTier = 3; } for (var i = 0; i < gameState.maxClustersPerType; i++) { maybeSpawnCluster('gold'); } } }, { id: 'double_gold', name: 'Double Gold Value', cost: 20000, multi: true, level: 0, maxLevel: 20, effect: 'Doubles Gold Value each purchase', action: function action() { this.level++; gameState.oreMultipliers.gold *= 2; this.cost *= 2; } }], diamond: [{ id: 'unlock_diamond', name: 'Unlock Diamond Mining', cost: 280000, effect: 'Allows diamond ore clusters to spawn', purchased: false, action: function action() { if (gameState.currentTier < 4) { gameState.currentTier = 4; } for (var i = 0; i < gameState.maxClustersPerType; i++) { maybeSpawnCluster('diamond'); } } }, { id: 'double_diamond', name: 'Double Diamond Value', cost: 50000, multi: true, level: 0, maxLevel: 20, effect: 'Doubles Diamond Value each purchase', action: function action() { this.level++; gameState.oreMultipliers.diamond *= 2; this.cost *= 2; } }], sapphire: [{ id: 'unlock_sapphire', name: 'Unlock Sapphire Mining', cost: 1400000, effect: 'Allows sapphire ore clusters to spawn', purchased: false, action: function action() { if (gameState.currentTier < 5) { gameState.currentTier = 5; } for (var i = 0; i < gameState.maxClustersPerType; i++) { maybeSpawnCluster('sapphire'); } } }, { id: 'double_sapphire', name: 'Double Sapphire Value', cost: 200000, multi: true, level: 0, maxLevel: 20, effect: 'Doubles Sapphire Value each purchase', action: function action() { this.level++; gameState.oreMultipliers.sapphire *= 2; this.cost *= 2; } }], emerald: [{ id: 'unlock_emerald', name: 'Unlock Emerald Mining', cost: 7000000, effect: 'Allows emerald ore clusters to spawn', purchased: false, action: function action() { if (gameState.currentTier < 6) { gameState.currentTier = 6; } for (var i = 0; i < gameState.maxClustersPerType; i++) { maybeSpawnCluster('emerald'); } } }, { id: 'double_emerald', name: 'Double Emerald Value', cost: 1000000, multi: true, level: 0, maxLevel: 20, effect: 'Doubles Emerald Value each purchase', action: function action() { this.level++; gameState.oreMultipliers.emerald *= 2; this.cost *= 2; } }], ruby: [{ id: 'unlock_ruby', name: 'Unlock Ruby Mining', cost: 14000000, effect: 'Allows ruby ore clusters to spawn', purchased: false, action: function action() { if (gameState.currentTier < 7) { gameState.currentTier = 7; } for (var i = 0; i < gameState.maxClustersPerType; i++) { maybeSpawnCluster('ruby'); } } }, { id: 'double_ruby', name: 'Double Ruby Value', cost: 2000000, multi: true, level: 0, maxLevel: 20, effect: 'Doubles Ruby Value each purchase', action: function action() { this.level++; gameState.oreMultipliers.ruby *= 2; this.cost *= 2; } }] }; var generalUpgrades = [{ id: 'faster_respawn', name: 'Quicker Respawn', cost: 8000, effect: 'Halves respawn time (min 500 ms)', multi: true, level: 0, maxLevel: 3, action: function action() { gameState.respawnTime = Math.max(500, gameState.respawnTime / 2); this.level++; this.cost = Math.floor(this.cost * 2); } }, { id: 'cluster_up', name: 'Cluster Growth', cost: 1000, effect: 'Increases cluster size range', multi: true, level: 0, maxLevel: 5, action: function action() { if (gameState.clusterUpgradeTier < gameState.clusterConfigLevels.length - 1) { gameState.clusterUpgradeTier++; } this.level++; this.cost += 2000; } }, { id: 'pickaxe_buff', name: 'Pickaxe DMG +20%', cost: 20000, effect: 'Increases your total pickaxe damage by 20%', multi: true, level: 0, maxLevel: 20, action: function action() { this.level++; gameState.pickaxeBaseMultiplier *= 1.2; this.cost = Math.floor(this.cost * 2); } }, { id: 'tap_damage', name: 'Tap Damage Upgrade', cost: 5000, effect: 'Increase tap damage by 50%', multi: true, level: 0, maxLevel: 20, action: function action() { this.level++; gameState.tapDamage *= 1.5; this.cost = Math.floor(this.cost * 2); } }, { id: 'miner_speed', name: 'Miner Swing Speed Upgrade', cost: 20000, effect: 'Increase miner swing speed (reduce cooldown by 10%)', multi: true, level: 0, maxLevel: 20, action: function action() { this.level++; miner.miningRate = Math.max(1, Math.floor(miner.miningRate * 0.9)); this.cost = Math.floor(this.cost * 2); } }]; var prestigeUpgrades = [{ id: 'pickaxe_plus_1', name: 'Pickaxe Level +1', cost: 3, effect: 'Increases pickaxe damage by 1', purchased: false, action: function action() { gameState.pickaxeLevel++; } }, { id: 'pickaxe_plus_2', name: 'Pickaxe Speed +10%', cost: 4, effect: 'Reduces mining cooldown by 10%', purchased: false, action: function action() { miner.miningRate = Math.floor(miner.miningRate * 0.90); if (miner.miningRate < 1) { miner.miningRate = 1; } } }, { id: 'pickaxe_plus_3', name: 'Pickaxe Bonus DMG +2', cost: 6, effect: 'Increases pickaxe damage by an additional 2', purchased: false, action: function action() { gameState.pickaxeLevel += 2; } }, { id: 'pickaxe_plus_4', name: 'Mega Pickaxe', cost: 15, effect: 'Increases pickaxe damage by an additional 5', purchased: false, action: function action() { gameState.pickaxeLevel += 5; } }]; var prestigeDrones = [{ id: 'drone_speedup', name: 'Drone Technology +1', cost: 8, effect: 'Increases Drone DPS by 50', purchased: false, action: function action() { if (!gameState.droneLevel) { gameState.droneLevel = 0; } gameState.droneLevel += 5; } }, { id: 'drone_overclock', name: 'Drone Overclock', cost: 12, effect: 'Increases Drone DPS by 100', purchased: false, action: function action() { gameState.droneLevel += 10; } }]; var droneUpgrades = [{ id: 'drone_level_1', name: 'Buy Drones (Lv +1)', cost: 5000, effect: 'Each level adds +10 DPS', purchased: false, multi: true, level: 0, maxLevel: 20, action: function action() { if (!gameState.droneLevel) { gameState.droneLevel = 0; } gameState.droneLevel++; this.level++; this.cost = Math.floor(this.cost * 1.5); updateDroneObjects(); } }]; /**** * UI ****/ // Create the upgrade menu container (always on top). var upgradeMenu = new Container(); upgradeMenu.zIndex = 10000; var tooltip = new Text2('', { size: 40, fill: 0xFFFFFF, stroke: 0x000000, strokeThickness: 4 }); game.addChild(tooltip); var moneyDisplay = new Text2('$0', { size: 80, fill: 0xFFFFFF, fontWeight: 'bold', stroke: 0x000000, strokeThickness: 4 }); moneyDisplay.x = 2048 / 2 - moneyDisplay.width / 2; moneyDisplay.y = 50; game.addChild(moneyDisplay); var prestigeDisplay = new Text2('Prestige: 0', { size: 50, fill: 0xFFFFFF, fontWeight: 'bold', stroke: 0x000000, strokeThickness: 4 }); prestigeDisplay.x = 250; prestigeDisplay.y = 50; game.addChild(prestigeDisplay); var shopOpenButton = LK.getAsset('shop_icon', { anchorX: 0.5, anchorY: 0.5 }); shopOpenButton.x = 2048 - 150; shopOpenButton.y = 2732 - 150; shopOpenButton.down = function () { createMainUpgradeMenu(); game.addChild(upgradeMenu); if (upgradeMenu.parent) { upgradeMenu.parent.setChildIndex(upgradeMenu, upgradeMenu.parent.children.length - 1); } }; game.addChild(shopOpenButton); // Test money button (modified to give $5 TRILLION). var addMoneyButton = LK.getAsset('test_money_button', { anchorX: 0.5, anchorY: 0.5 }); addMoneyButton.x = 200; addMoneyButton.y = 2732 - 300; addMoneyButton.down = function () { gameState.money += 5000000000000; updateUI(); }; game.addChild(addMoneyButton); /**** * UPGRADE MODAL HELPER ****/ function showUpgradeModal(upg, btn, callback) { var modal = new Container(); var bg = LK.getAsset('upgrade_popup_bg', { anchorX: 0.5, anchorY: 0.5 }); modal.addChild(bg); var nextCost = upg.multi ? Math.floor(upg.cost * 2) : upg.cost; var textStr = upg.effect + "\nCost: $" + upg.cost; if (upg.multi) { textStr += " Next: $" + nextCost; } var desc = new Text2(textStr, { size: 35, fill: 0x000000, stroke: 0x000000, strokeThickness: 4, align: 'center', fontWeight: 'bold' }); desc.anchor.set(0.5); desc.y = -50; modal.addChild(desc); var upgradeBtn = LK.getAsset('upgrade_confirm_button', { anchorX: 0.5, anchorY: 0.5 }); upgradeBtn.x = -100; upgradeBtn.y = 50; modal.addChild(upgradeBtn); var upgradeTxt = new Text2("Upgrade", { size: 35, fill: 0x000000, stroke: 0xFFFFFF, strokeThickness: 4, align: 'center', fontWeight: 'bold' }); upgradeTxt.anchor.set(0.5); upgradeTxt.x = upgradeBtn.x; upgradeTxt.y = upgradeBtn.y; modal.addChild(upgradeTxt); var cancelBtn = LK.getAsset('cancelButton', { anchorX: 0.5, anchorY: 0.5 }); cancelBtn.x = 100; cancelBtn.y = 50; modal.addChild(cancelBtn); modal.x = btn.x; modal.y = btn.y - 150; upgradeMenu.addChild(modal); if (upgradeMenu.parent) { upgradeMenu.parent.setChildIndex(upgradeMenu, upgradeMenu.parent.children.length - 1); } upgradeBtn.down = function () { callback(true); modal.destroy(); }; cancelBtn.down = function () { callback(false); modal.destroy(); }; upgradeMenu.down = function (event) { modal.destroy(); }; } /**** * PRESTIGE MODAL ****/ function showPrestigeModal() { var modal = new Container(); var popup = LK.getAsset('prestige_popup', { anchorX: 0.5, anchorY: 0.5 }); modal.addChild(popup); var req = getPrestigeRequirement(); var prompt = new Text2("Prestige?\nYou need: $" + req.toLocaleString() + "\nYou have: $" + Math.floor(gameState.money).toLocaleString(), { size: 40, fill: 0xFFFFFF, stroke: 0x000000, strokeThickness: 4, align: 'center', fontWeight: 'bold' }); prompt.anchor.set(0.5); modal.addChild(prompt); popup.x = 0; popup.y = 0; prompt.x = 0; prompt.y = -30; var yesBtn = LK.getAsset('yes_button', { anchorX: 0.5, anchorY: 0.5 }); yesBtn.x = -100; yesBtn.y = 60; modal.addChild(yesBtn); var noBtn = LK.getAsset('cancelButton', { anchorX: 0.5, anchorY: 0.5 }); noBtn.x = 100; noBtn.y = 60; modal.addChild(noBtn); modal.x = 2048 / 2; modal.y = 2732 / 2; upgradeMenu.addChild(modal); yesBtn.down = function () { if (canPrestige()) { doPrestige(); modal.destroy(); upgradeMenu.removeChild(modal); } }; noBtn.down = function () { modal.destroy(); upgradeMenu.removeChild(modal); }; upgradeMenu.down = function (event) { modal.destroy(); }; } /**** * MAIN UPGRADE MENU ****/ function createMainUpgradeMenu() { upgradeMenu.removeChildren(); subUpgradeItemRefs = []; var menuBg = LK.getAsset('rectangle', { width: 1800, height: 2200, color: 0x2a2a2a, anchorX: 0.5, anchorY: 0.5 }); menuBg.alpha = 0.9; menuBg.x = 2048 / 2; menuBg.y = 2732 / 2 + 50; upgradeMenu.addChild(menuBg); var categories = [{ name: 'Coal Upgrades', type: 'coal' }, { name: 'Iron Upgrades', type: 'iron' }, { name: 'Gold Upgrades', type: 'gold' }, { name: 'Diamond Upgrades', type: 'diamond' }, { name: 'Sapphire Upgrades', type: 'sapphire' }, { name: 'Emerald Upgrades', type: 'emerald' }, { name: 'Ruby Upgrades', type: 'ruby' }, { name: 'General Upgrades', type: 'general' }, { name: 'Drones', type: 'drones' }, { name: 'Achievements', type: 'achievements' }, { name: 'Prestige', type: 'prestige' }, { name: 'Game Stats', type: 'stats' }]; var colSpacing = 400, rowSpacing = 300; for (var i = 0; i < categories.length; i++) { var col = i % 2, row = Math.floor(i / 2); var x = menuBg.x + (col === 0 ? -colSpacing : colSpacing); var y = menuBg.y - 800 + row * rowSpacing; var btn = LK.getAsset('buy_button', { anchorX: 0.5, anchorY: 0.5 }); btn.x = x; btn.y = y; upgradeMenu.addChild(btn); var txt = new Text2(categories[i].name, { size: 50, fill: 0x000000, stroke: 0xFFFFFF, strokeThickness: 4, align: 'center', fontWeight: 'bold' }); txt.anchor.set(0.5); txt.x = btn.x; txt.y = btn.y; upgradeMenu.addChild(txt); btn.down = function (cat) { return function (event) { event.stopPropagation && event.stopPropagation(); hideUpgradeDesc(); if (cat.type === 'general') { createSubUpgradeMenu('General Upgrades', generalUpgrades); } else if (cat.type === 'drones') { createSubUpgradeMenu('Drone Upgrades', droneUpgrades); } else if (cat.type === 'achievements') { createAchievementsMenu(); } else if (cat.type === 'prestige') { createPrestigeMenu(); } else if (cat.type === 'stats') { createStatsMenu(); } else { createSubUpgradeMenu(cat.name, oreUpgrades[cat.type]); } }; }(categories[i]); } var closeBtn = LK.getAsset('cancelButton', { anchorX: 0.5, anchorY: 0.5 }); closeBtn.x = menuBg.x + 750; closeBtn.y = menuBg.y - 950; closeBtn.down = function () { game.removeChild(upgradeMenu); }; upgradeMenu.addChild(closeBtn); upgradeMenu.down = function (event) { hideUpgradeDesc(); }; if (upgradeMenu.parent) { upgradeMenu.parent.setChildIndex(upgradeMenu, upgradeMenu.parent.children.length - 1); } } var subUpgradeItemRefs = []; function createSubUpgradeMenu(title, upgList) { upgradeMenu.removeChildren(); subUpgradeItemRefs = []; var menuBg = LK.getAsset('rectangle', { width: 1800, height: 2200, color: 0x2a2a2a, anchorX: 0.5, anchorY: 0.5 }); menuBg.alpha = 0.9; menuBg.x = 2048 / 2; menuBg.y = 2732 / 2 + 50; upgradeMenu.addChild(menuBg); var titleText = new Text2(title, { size: 60, fill: 0x000000, stroke: 0xFFFFFF, strokeThickness: 4, align: 'center', fontWeight: 'bold' }); titleText.anchor.set(0.5); titleText.x = menuBg.x; titleText.y = menuBg.y - 1000; upgradeMenu.addChild(titleText); var startY = menuBg.y - 800, colSpacing = 400; for (var i = 0; i < upgList.length; i++) { var col = i % 2, row = Math.floor(i / 2); var btn = LK.getAsset('buy_button', { anchorX: 0.5, anchorY: 0.5 }); btn.x = menuBg.x + (col === 0 ? -colSpacing : colSpacing); btn.y = startY + row * 250; upgradeMenu.addChild(btn); var displayName = upgList[i].name; if (typeof upgList[i].level === 'number' && upgList[i].level > 0) { displayName += " (Lv " + upgList[i].level + ")"; } var txt = new Text2(displayName + "\nCost: $" + upgList[i].cost, { size: 45, fill: 0x000000, stroke: 0xFFFFFF, strokeThickness: 4, align: 'center', fontWeight: 'bold' }); txt.anchor.set(0.5); txt.x = btn.x; txt.y = btn.y; upgradeMenu.addChild(txt); btn.down = function (upg, btn) { return function (event) { event.stopPropagation && event.stopPropagation(); showUpgradeModal(upg, btn, function (confirmed) { if (confirmed && canPurchaseUpgrade(upgList, upg)) { gameState.money -= upg.cost; upg.purchased = true; upg.action(); updateUI(); createSubUpgradeMenu(title, upgList); } }); }; }(upgList[i], btn); subUpgradeItemRefs.push({ upgList: upgList, upgrade: upgList[i], textObj: txt }); } var backBtn = LK.getAsset('cancelButton', { anchorX: 0.5, anchorY: 0.5 }); backBtn.x = menuBg.x + 700; backBtn.y = menuBg.y - 1000; backBtn.down = function () { createMainUpgradeMenu(); }; upgradeMenu.addChild(backBtn); upgradeMenu.down = function (event) { hideUpgradeDesc(); }; } function canPurchaseUpgrade(upgList, upg) { if (upg.requires) { var needed = upgList.find(function (u) { return u.id === upg.requires; }); if (!needed || !needed.purchased) { return false; } } if (upg.multi && upg.maxLevel !== undefined && upg.level >= upg.maxLevel) { return false; } if (!upg.multi && upg.purchased) { return false; } if (gameState.money < upg.cost) { return false; } return true; } /**** * GAME LOOP ****/ var quantumSelectTimer = 0, quantumSelectionActive = false; game.update = function () { if (!gamePaused && miner) { miner.update(); } for (var i = 0; i < droneObjects.length; i++) { droneObjects[i].updateDrone(); } if (typeof LK.time !== 'undefined' && LK.time.elapsed % 60 === 0) { droneDamageTick(); } clusters.forEach(function (cluster) { cluster.oreList.forEach(function (ore) { if (ore.health > 0) { var fraction = ore.health / ore.maxHealth; ore.healthBar.width = 120 * fraction; ore.healthBar.fill = interpolateColor(0xFF0000, 0x00FF00, fraction); ore.alpha = fraction; } }); }); if (upgradeMenu.parent) { subUpgradeItemRefs.forEach(function (ref) { var upg = ref.upgrade; var canBuy = canPurchaseUpgrade(ref.upgList, upg); if (ref.textObj && ref.textObj.style) { ref.textObj.style.fill = canBuy ? 0xFFFFFF : 0x666666; } }); } // Update dynamic game stats if the stats menu is open. if (statsTextObj) { var oreTypes = ['coal', 'iron', 'gold', 'diamond', 'sapphire', 'emerald', 'ruby', 'chronostone', 'soulember', 'quantumshard']; var oreStats = ""; oreTypes.forEach(function (type) { var oreName = type.charAt(0).toUpperCase() + type.slice(1); oreStats += oreName + " Mined: " + (gameState.oreMined[type] || 0) + "\n"; }); var newStatsText = ""; newStatsText += oreStats; newStatsText += "Total Money Earned: $" + gameState.totalMoneyEarned.toLocaleString() + "\n"; var achievedCount = achievements.filter(function (a) { return a.achieved; }).length; newStatsText += "Achievements: " + achievedCount + "/" + achievements.length + "\n"; newStatsText += "Prestige Count: " + gameState.prestigeCount + "\n"; var timePlayed = Math.floor((Date.now() - gameState.startTime) / 1000); newStatsText += "Time Played: " + timePlayed + " sec\n"; newStatsText += "Ore Taps: " + gameState.tapCount + "\n"; newStatsText += "Miner Hits: " + gameState.minerHitCount + "\n"; var fullyUpgraded = 0; for (var key in oreUpgrades) { oreUpgrades[key].forEach(function (upg) { if (upg.level >= upg.maxLevel) { fullyUpgraded++; } }); } newStatsText += "Fully Upgraded Ore Upgrades: " + fullyUpgraded + "\n"; statsTextObj.setText(newStatsText); } // Update Chronostone effect timer and overlay. if (chronostoneActive) { chronostoneTimer--; if (chronostoneTimerText) { var secondsLeft = Math.ceil(chronostoneTimer / 60); chronostoneTimerText.setText(secondsLeft.toString()); } if (chronostoneTimer <= 0) { chronostoneActive = false; if (chronostoneOverlay && chronostoneOverlay.parent) { chronostoneOverlay.parent.removeChild(chronostoneOverlay); chronostoneOverlay.destroy(); chronostoneOverlay = null; } if (chronostoneTimerText && chronostoneTimerText.parent) { chronostoneTimerText.parent.removeChild(chronostoneTimerText); chronostoneTimerText.destroy(); chronostoneTimerText = null; } if (miner) { miner.speedBoostMultiplier /= 2; } chronostoneBannerShown = false; } } // Update Quantum Shard effect (mini miners). if (quantumShardActive) { quantumShardTimer--; miniMiners.forEach(function (mini) { mini.update(); }); if (quantumShardTimer <= 0) { miniMiners.forEach(function (mini) { if (mini.parent) { mini.parent.removeChild(mini); } }); miniMiners = []; quantumShardActive = false; if (quantumShardOverlay && quantumShardOverlay.parent) { quantumShardOverlay.parent.removeChild(quantumShardOverlay); quantumShardOverlay.destroy(); quantumShardOverlay = null; } quantumShardBannerShown = false; } } achievements.forEach(function (ach) { if (!ach.achieved && ach.condition()) { ach.achieved = true; var achText = new Text2("Achievement Unlocked: " + ach.name, { size: 40, fill: 0xFFFF00, stroke: 0x000000, strokeThickness: 4, fontWeight: 'bold' }); achText.x = 2048 / 2; achText.y = 100; game.addChild(achText); tween(achText, { alpha: 0 }, { duration: 2000, onFinish: function onFinish() { achText.destroy(); } }); } }); if (canPrestige()) { if (!prestigeMainButton) { prestigeMainButton = LK.getAsset('prestige_main_button', { anchorX: 0.5, anchorY: 0.5 }); prestigeMainButton.x = 150; prestigeMainButton.y = 2732 - 150; prestigeMainButton.down = function () { doPrestige(); if (prestigeMainButton && prestigeMainButton.parent) { prestigeMainButton.parent.removeChild(prestigeMainButton); prestigeMainButton = null; } }; game.addChild(prestigeMainButton); } } else { if (prestigeMainButton) { if (prestigeMainButton.parent) { prestigeMainButton.parent.removeChild(prestigeMainButton); } prestigeMainButton = null; } } if (upgradeMenu && upgradeMenu.parent) { upgradeMenu.parent.setChildIndex(upgradeMenu, upgradeMenu.parent.children.length - 1); } }; function droneDamageTick() { var dps = getDroneDPS(); if (dps <= 0) { return; } var allValidOres = []; clusters.forEach(function (c) { c.oreList.forEach(function (ore) { if (ore.health > 0 && ore.tier <= gameState.currentTier) { allValidOres.push(ore); } }); }); if (allValidOres.length === 0) { return; } var damageRemaining = dps; while (damageRemaining > 0 && allValidOres.length > 0) { var randomIndex = Math.floor(Math.random() * allValidOres.length); var ore = allValidOres[randomIndex]; var chunk = Math.min(damageRemaining, 10); ore.health -= chunk; damageRemaining -= chunk; if (ore.health <= 0) { var baseValue = ore.getValue(); gameState.money += baseValue; updateUI(); ore.cluster.notifyOreDestroyed(ore); spawnMiningParticles(ore, 5); allValidOres.splice(randomIndex, 1); } } } /**** * UI REFRESH & SAVE/LOAD ****/ function updateUI() { moneyDisplay.setText("$" + Math.floor(gameState.money).toLocaleString()); moneyDisplay.x = 2048 / 2 - moneyDisplay.width / 2; prestigeDisplay.setText("Prestige: " + gameState.prestigeCount); } LK.saveGame = function () { return gameState; }; LK.loadGame = function (data) { gameState = data; updateUI(); }; /**** * START GAME ****/ function startGame() { currentBackground = LK.getAsset('background', { anchorX: 0.5, anchorY: 0.5 }); currentBackground.x = 2048 / 2; currentBackground.y = 2732 / 2; currentBackground.zIndex = -100; game.addChildAt(currentBackground, 0); miner = new Miner(); miner.x = 2048 / 2; miner.y = 2732 / 2; game.addChild(miner); initialSpawn(); updateUI(); } startGame(); game.pauseForQuantumSelection = function () { quantumSelectionActive = true; quantumSelectTimer = 0; }; function createPrestigeMenu() { upgradeMenu.removeChildren(); var menuBg = LK.getAsset('rectangle', { width: 1800, height: 2200, color: 0x444444, anchorX: 0.5, anchorY: 0.5 }); menuBg.alpha = 0.9; menuBg.x = 2048 / 2; menuBg.y = 2732 / 2 + 50; upgradeMenu.addChild(menuBg); var titleText = new Text2("Prestige Upgrades", { size: 60, fill: 0xFFFFFF, stroke: 0x000000, strokeThickness: 4, align: "center", fontWeight: 'bold' }); titleText.anchor.set(0.5); titleText.x = menuBg.x; titleText.y = menuBg.y - 1000; upgradeMenu.addChild(titleText); var startY = menuBg.y - 800; var colSpacing = 400; for (var i = 0; i < prestigeUpgrades.length; i++) { var col = i % 2, row = Math.floor(i / 2); var btn = LK.getAsset('buy_button', { anchorX: 0.5, anchorY: 0.5 }); btn.x = menuBg.x + (col === 0 ? -colSpacing : colSpacing); btn.y = startY + row * 250; upgradeMenu.addChild(btn); var displayName = prestigeUpgrades[i].name; var txt = new Text2(displayName + "\nCost: " + prestigeUpgrades[i].cost + " Shards", { size: 45, fill: 0x000000, stroke: 0xFFFFFF, strokeThickness: 4, align: 'center', fontWeight: 'bold' }); txt.anchor.set(0.5); txt.x = btn.x; txt.y = btn.y; upgradeMenu.addChild(txt); btn.down = function (upg, btn) { return function (event) { event.stopPropagation && event.stopPropagation(); showUpgradeModal(upg, btn, function (confirmed) { if (confirmed && canPurchaseUpgrade(prestigeUpgrades, upg)) { gameState.prestigeCurrency -= upg.cost; upg.purchased = true; upg.action(); updateUI(); createPrestigeMenu(); } }); }; }(prestigeUpgrades[i], btn); } var backBtn = LK.getAsset('cancelButton', { anchorX: 0.5, anchorY: 0.5 }); backBtn.x = menuBg.x + 700; backBtn.y = menuBg.y - 1000; backBtn.down = function () { createMainUpgradeMenu(); }; upgradeMenu.addChild(backBtn); } function createAchievementsMenu() { upgradeMenu.removeChildren(); var menuBg = LK.getAsset('rectangle', { width: 1800, height: 2200, color: 0x333333, anchorX: 0.5, anchorY: 0.5 }); menuBg.alpha = 0.9; menuBg.x = 2048 / 2; menuBg.y = 2732 / 2 + 50; upgradeMenu.addChild(menuBg); var titleText = new Text2("Achievements", { size: 60, fill: 0x000000, stroke: 0xFFFFFF, strokeThickness: 4, align: "center", fontWeight: 'bold' }); titleText.anchor.set(0.5); titleText.x = menuBg.x; titleText.y = menuBg.y - 1000; upgradeMenu.addChild(titleText); var yStart = menuBg.y - 800, spacing = 150; achievements.forEach(function (ach, index) { var container = new Container(); container.x = menuBg.x; container.y = yStart + index * spacing; var title = new Text2(ach.name, { size: 50, fill: 0x000000, stroke: 0xFFFFFF, strokeThickness: 4, fontWeight: 'bold' }); title.anchor.set(0.5); container.addChild(title); if (ach.target !== undefined) { var currentProgress = ach.id === 'coal_miner' ? gameState.oreMined.coal : 0; var progressBarBg = LK.getAsset('achievement_bar', { width: 400, height: 30, color: 0x555555, anchorX: 0, anchorY: 0.5 }); progressBarBg.x = -200; progressBarBg.y = 50; container.addChild(progressBarBg); var progressWidth = Math.min(currentProgress / ach.target * 400, 400); var progressBarFg = LK.getAsset('rectangle', { width: progressWidth, height: 30, color: 0x00FF00, anchorX: 0, anchorY: 0.5 }); progressBarFg.x = -200; progressBarFg.y = 50; container.addChild(progressBarFg); var progressText = new Text2(currentProgress + "/" + ach.target, { size: 30, fill: 0x000000, stroke: 0xFFFFFF, strokeThickness: 4, fontWeight: 'bold' }); progressText.anchor.set(0.5); progressText.x = 0; progressText.y = 50; container.addChild(progressText); } if (ach.achieved) { var achievedText = new Text2("Achieved!", { size: 30, fill: 0x000000, stroke: 0xFFFFFF, strokeThickness: 4, fontWeight: 'bold' }); achievedText.anchor.set(0.5); achievedText.x = 300; achievedText.y = 0; container.addChild(achievedText); } upgradeMenu.addChild(container); }); var backBtn = LK.getAsset('cancelButton', { anchorX: 0.5, anchorY: 0.5 }); backBtn.x = menuBg.x + 700; backBtn.y = menuBg.y - 1000; backBtn.down = function () { createMainUpgradeMenu(); }; upgradeMenu.addChild(backBtn); } function createStatsMenu() { upgradeMenu.removeChildren(); var menuBg = LK.getAsset('rectangle', { width: 1800, height: 2200, color: 0x222222, anchorX: 0.5, anchorY: 0.5 }); menuBg.alpha = 0.9; menuBg.x = 2048 / 2; menuBg.y = 2732 / 2 + 50; upgradeMenu.addChild(menuBg); var titleText = new Text2("Game Stats", { size: 60, fill: 0x000000, stroke: 0xFFFFFF, strokeThickness: 4, align: "center", fontWeight: 'bold' }); titleText.anchor.set(0.5); titleText.x = menuBg.x; titleText.y = menuBg.y - 1000; upgradeMenu.addChild(titleText); var oreTypes = ['coal', 'iron', 'gold', 'diamond', 'sapphire', 'emerald', 'ruby', 'chronostone', 'soulember', 'quantumshard']; var yStart = menuBg.y - 800, spacing = 60; oreTypes.forEach(function (type, index) { var statContainer = new Container(); statContainer.x = menuBg.x - 600; statContainer.y = yStart + index * spacing; var oreAsset = LK.getAsset(type + '_ore', { anchorX: 0.5, anchorY: 0.5 }); oreAsset.scale = 0.5; oreAsset.x = 0; oreAsset.y = 0; statContainer.addChild(oreAsset); var oreName = type.charAt(0).toUpperCase() + type.slice(1); var countText = new Text2(oreName + " Mined: " + (gameState.oreMined[type] || 0), { size: 40, fill: 0x000000, stroke: 0x000000, strokeThickness: 4, fontWeight: 'bold' }); countText.x = 100; countText.y = 0; statContainer.addChild(countText); upgradeMenu.addChild(statContainer); }); var statsText = ""; statsText += "Total Money Earned: $" + gameState.totalMoneyEarned.toLocaleString() + "\n"; var achievedCount = achievements.filter(function (a) { return a.achieved; }).length; statsText += "Achievements: " + achievedCount + "/" + achievements.length + "\n"; statsText += "Prestige Count: " + gameState.prestigeCount + "\n"; var timePlayed = Math.floor((Date.now() - gameState.startTime) / 1000); statsText += "Time Played: " + timePlayed + " sec\n"; statsText += "Ore Taps: " + gameState.tapCount + "\n"; statsText += "Miner Hits: " + gameState.minerHitCount + "\n"; var fullyUpgraded = 0; for (var key in oreUpgrades) { oreUpgrades[key].forEach(function (upg) { if (upg.level >= upg.maxLevel) { fullyUpgraded++; } }); } statsText += "Fully Upgraded Ore Upgrades: " + fullyUpgraded + "\n"; // Create the stats text object and store it in the global variable for dynamic updating. statsTextObj = new Text2(statsText, { size: 40, fill: 0x000000, stroke: 0x000000, strokeThickness: 4, fontWeight: 'bold' }); statsTextObj.x = menuBg.x + 200; statsTextObj.y = menuBg.y - 800; upgradeMenu.addChild(statsTextObj); var backBtn = LK.getAsset('cancelButton', { anchorX: 0.5, anchorY: 0.5 }); backBtn.x = menuBg.x + 700; backBtn.y = menuBg.y - 1000; backBtn.down = function () { createMainUpgradeMenu(); }; upgradeMenu.addChild(backBtn); }
===================================================================
--- original.js
+++ change.js
@@ -5,55 +5,335 @@
/****
* Classes
****/
-/** Cluster – represents a group of ores **/
+/****
+* CLASSES
+****/
+/** Cluster – spawns multiple ore objects. **/
var Cluster = Container.expand(function (type) {
var self = Container.call(this);
self.type = type;
self.oreList = [];
- self.x = 0;
- self.y = 0;
- // Initialize ores within the cluster
- var numOres = randomInt(gameState.clusterConfig.min, gameState.clusterConfig.max);
- for (var i = 0; i < numOres; i++) {
+ self.zIndex = 0;
+ // Use the helper to generate a valid spawn position (avoiding UI areas)
+ var center = getValidClusterCenter();
+ self.x = center.x;
+ self.y = center.y;
+ var cc = gameState.clusterConfig;
+ var count = randomInt(cc.min, cc.max);
+ for (var i = 0; i < count; i++) {
var ore = new Ore(type, self);
- ore.x = (Math.random() - 0.5) * 200;
- ore.y = (Math.random() - 0.5) * 200;
+ ore.x = (Math.random() - 0.5) * 120;
+ ore.y = (Math.random() - 0.5) * 120;
self.oreList.push(ore);
self.addChild(ore);
}
- // Notify when an ore is destroyed
+ // Modified: Increment ore mined for each ore (not once per cluster)
self.notifyOreDestroyed = function (ore) {
- var index = self.oreList.indexOf(ore);
- if (index !== -1) {
- self.oreList.splice(index, 1);
+ var idx = self.oreList.indexOf(ore);
+ if (idx >= 0) {
+ self.oreList.splice(idx, 1);
}
ore.destroy();
+ // Increment individual ore mined stat here.
+ gameState.oreMined[type] = (gameState.oreMined[type] || 0) + 1;
+ if (self.oreList.length === 0) {
+ if (self.parent) {
+ self.parent.removeChild(self);
+ }
+ var cidx = clusters.indexOf(self);
+ if (cidx >= 0) {
+ clusters.splice(cidx, 1);
+ }
+ gameState.clusterCount[type]--;
+ var finalDelay = gameState.respawnTime;
+ if (type === 'coal') {
+ finalDelay *= 2;
+ }
+ LK.setTimeout(function () {
+ maybeSpawnCluster(type);
+ }, finalDelay);
+ }
};
return self;
});
-/** Miner – the main miner class (assumed to be defined similarly) **/
+/** Drone – moves and zaps ores. **/
+var Drone = Container.expand(function () {
+ var self = Container.call(this);
+ self.droneSprite = LK.getAsset('drone_asset', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.addChild(self.droneSprite);
+ self.AOE_RANGE = 150;
+ self.droneDamage = 2;
+ self.COOLDOWN_MAX = 60;
+ self.cooldown = 0;
+ var SPEED = 8,
+ MIN_X = 50,
+ MAX_X = 2000,
+ MIN_Y = 50,
+ MAX_Y = 2682;
+ self.vx = Math.random() < 0.5 ? SPEED : -SPEED;
+ self.vy = Math.random() < 0.5 ? SPEED : -SPEED;
+ self.updateDrone = function () {
+ self.x += self.vx;
+ self.y += self.vy;
+ if (self.x < MIN_X || self.x > MAX_X) {
+ self.vx = -self.vx;
+ }
+ if (self.y < MIN_Y || self.y > MAX_Y) {
+ self.vy = -self.vy;
+ }
+ if (Math.random() < 0.01) {
+ self.vx += (Math.random() - 0.5) * 2;
+ self.vy += (Math.random() - 0.5) * 2;
+ var speed = Math.sqrt(self.vx * self.vx + self.vy * self.vy);
+ if (speed > SPEED) {
+ self.vx = self.vx / speed * SPEED;
+ self.vy = self.vy / speed * SPEED;
+ }
+ }
+ self.droneSprite.rotation += 0.1;
+ if (self.cooldown > 0) {
+ self.cooldown--;
+ } else {
+ self.tryZap();
+ }
+ };
+ self.tryZap = function () {
+ var hitSomething = false;
+ clusters.forEach(function (cluster) {
+ cluster.oreList.forEach(function (ore) {
+ if (ore.health > 0) {
+ var oreGlobalX = cluster.x + ore.x,
+ oreGlobalY = cluster.y + ore.y;
+ var dx = self.x - oreGlobalX,
+ dy = self.y - oreGlobalY;
+ var dist = Math.sqrt(dx * dx + dy * dy);
+ if (dist < self.AOE_RANGE) {
+ var damage = self.droneDamage;
+ var actualDamage = Math.min(damage, ore.health);
+ var fraction = actualDamage / ore.maxHealth;
+ var reward = Math.round(fraction * ore.getValue());
+ if (ore.awardedMoney + reward > ore.getValue()) {
+ reward = ore.getValue() - ore.awardedMoney;
+ }
+ ore.awardedMoney += reward;
+ gameState.money += reward;
+ gameState.totalMoneyEarned += reward;
+ updateUI();
+ ore.health -= actualDamage;
+ hitSomething = true;
+ spawnDroneAOE(ore);
+ if (ore.health <= 0) {
+ ore.cluster.notifyOreDestroyed(ore);
+ spawnMiningParticles(ore, 5);
+ } else {
+ spawnMiningParticles(ore, 2);
+ }
+ // Show floating text for drone hit (red)
+ showFloatingText(reward, 0xFF0000);
+ }
+ }
+ });
+ });
+ if (hitSomething) {
+ LK.getSound('drone_shot').play();
+ self.cooldown = self.COOLDOWN_MAX;
+ }
+ };
+ return self;
+});
+/** Miner – moves toward and mines the nearest ore. **/
var Miner = Container.expand(function () {
var self = Container.call(this);
self.attachAsset('miner', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 5;
- self.miningDamage = 1;
- self.miningRate = 60;
self.currentTarget = null;
+ self.miningRange = 25;
+ self.miningCooldown = 0;
+ self.miningRate = 60;
+ self.miningDamage = 1;
+ self.originalMiningRate = self.miningRate;
+ self.originalMiningDamage = self.miningDamage;
+ self.speedBoostMultiplier = 1;
+ self.speedBoostTimer = 0;
+ self.soulEmberStacks = 0;
+ self.quantumPathActive = false;
+ self.quantumPath = [];
+ self.quantumShardValueBonus = false;
+ self.hyperMiningActive = false;
+ self.hyperMiningTimer = 0;
+ // (Other methods remain unchanged.)
+ // Update method (modified to account for pause and special effects)
self.update = function () {
- // (Miner update logic remains unchanged.)
+ if (self.hyperMiningActive) {
+ self.hyperMiningTimer--;
+ if (self.hyperMiningTimer <= 0) {
+ self.miningDamage = self.originalMiningDamage;
+ self.miningRate = self.originalMiningRate;
+ self.hyperMiningActive = false;
+ }
+ }
+ if (self.speedBoostTimer > 0) {
+ self.speedBoostTimer--;
+ if (self.speedBoostTimer <= 0) {
+ self.speedBoostMultiplier = 1;
+ }
+ }
+ self.findNewTarget();
+ if (self.currentTarget && self.currentTarget.parent) {
+ var tx = self.currentTarget.parent.x + self.currentTarget.x,
+ ty = self.currentTarget.parent.y + self.currentTarget.y;
+ var dx = tx - self.x,
+ dy = ty - self.y,
+ dist = Math.sqrt(dx * dx + dy * dy);
+ var finalSpeed = self.speed * self.speedBoostMultiplier;
+ if (dist > self.miningRange) {
+ self.x += dx / dist * finalSpeed;
+ self.y += dy / dist * finalSpeed;
+ } else {
+ self.mineOre(self.currentTarget);
+ }
+ } else {
+ self.currentTarget = null; // Ensure currentTarget is reset if undefined
+ if (typeof LK.time !== 'undefined') {
+ self.y += Math.sin(LK.time.elapsed / 250) * 0.5;
+ }
+ }
};
- // (Additional miner methods…)
+ self.findNewTarget = function () {
+ if (self.quantumPathActive && self.quantumPath.length > 0) {
+ self.currentTarget = self.quantumPath[0];
+ if (!self.currentTarget || self.currentTarget.health <= 0) {
+ self.quantumPath.shift();
+ if (self.quantumPath.length === 0) {
+ self.quantumShardValueBonus = false;
+ self.quantumPathActive = false;
+ self.currentTarget = null;
+ }
+ return;
+ }
+ return;
+ }
+ var validOre = [];
+ clusters.forEach(function (c) {
+ c.oreList.forEach(function (ore) {
+ if (ore.health > 0 && (ore.tier <= gameState.currentTier || ore.type === "chronostone" || ore.type === "soulember" || ore.type === "quantumshard")) {
+ validOre.push(ore);
+ }
+ });
+ });
+ if (validOre.length === 0) {
+ self.currentTarget = null;
+ return;
+ }
+ self.currentTarget = validOre.sort(function (a, b) {
+ var aX = a.parent.x + a.x,
+ aY = a.parent.y + a.y;
+ var bX = b.parent.x + b.x,
+ bY = b.parent.y + b.y;
+ return Math.hypot(aX - self.x, aY - self.y) - Math.hypot(bX - self.x, bY - self.y);
+ })[0];
+ };
+ // Modified mineOre to account for soul ember boost.
+ self.mineOre = function (ore) {
+ if (self.miningCooldown > 0) {
+ self.miningCooldown--;
+ return;
+ }
+ var damageDealt = self.miningDamage * gameState.pickaxeLevel * (gameState.pickaxeBaseMultiplier || 1);
+ // If Soul Ember boost is active, double the damage and reward.
+ if (soulEmberActive && soulEmberBoostCount > 0) {
+ damageDealt *= 2;
+ }
+ var actualDamage = Math.min(damageDealt, ore.health);
+ var fraction = actualDamage / ore.maxHealth;
+ var rewardMultiplier = 1;
+ if (soulEmberActive && soulEmberBoostCount > 0) {
+ rewardMultiplier = 2;
+ }
+ var reward = Math.round(fraction * ore.getValue() * rewardMultiplier);
+ if (ore.awardedMoney + reward > ore.getValue()) {
+ reward = ore.getValue() - ore.awardedMoney;
+ }
+ ore.awardedMoney += reward;
+ gameState.money += reward;
+ gameState.totalMoneyEarned += reward;
+ gameState.minerHitCount++;
+ updateUI();
+ var mineSound = LK.getSound('mine_' + ore.type);
+ if (mineSound) {
+ mineSound.play();
+ }
+ ore.health -= actualDamage;
+ self.miningCooldown = self.miningRate;
+ if (ore.health <= 0) {
+ spawnMiningParticles(ore, 5);
+ var destroySound = LK.getSound('ore_destroy_' + ore.type);
+ if (destroySound) {
+ destroySound.play();
+ }
+ if (ore.type === "explosive" && ore.explode) {
+ ore.explode();
+ // If explosive ore and prestige >=12 and no meteor shower active, trigger meteor shower.
+ if (gameState.prestigeCount >= 12 && !meteorShowerActive) {
+ triggerMeteorShowerEffect();
+ }
+ }
+ ore.cluster.notifyOreDestroyed(ore);
+ // If Soul Ember boost is active, decrease its counter and show boosted floating text.
+ if (soulEmberActive && soulEmberBoostCount > 0) {
+ soulEmberBoostCount--;
+ showFloatingText(reward, 0xFFD700); // Gold, bold floating text
+ if (soulEmberBoostCount <= 0) {
+ soulEmberActive = false;
+ if (soulEmberOverlay && soulEmberOverlay.parent) {
+ soulEmberOverlay.parent.removeChild(soulEmberOverlay);
+ soulEmberOverlay.destroy();
+ soulEmberOverlay = null;
+ }
+ soulEmberBannerShown = false;
+ }
+ } else {
+ // Normal floating text for miner hit (green)
+ showFloatingText(reward, 0x00FF00);
+ }
+ // Trigger special ore effects if applicable.
+ if (ore.type === "chronostone" && !chronostoneActive) {
+ triggerChronostoneEffect();
+ }
+ if (ore.type === "soulember" && !soulEmberActive) {
+ triggerSoulEmberEffect();
+ }
+ if (ore.type === "quantumshard" && !quantumShardActive) {
+ triggerQuantumShardEffect();
+ }
+ } else {
+ spawnMiningParticles(ore, 2);
+ showFloatingText(reward, 0x00FF00);
+ }
+ };
+ self.applyChronostoneBoost = function () {
+ self.speedBoostMultiplier *= 3;
+ self.speedBoostTimer = 30 * 60; // 30 sec boost
+ };
+ self.applySoulEmberBoost = function () {
+ // (Deprecated – now handled in triggerSoulEmberEffect)
+ };
+ self.triggerQuantumShardMode = function () {
+ self.quantumShardValueBonus = true;
+ self.quantumPathActive = true;
+ self.quantumPath = [];
+ game.pauseForQuantumSelection();
+ };
return self;
});
-/****
-* SPECIAL EFFECTS FUNCTIONS
-****/
-// Background transition function – fixed to work on every prestige
/** MiniMiner – spawned by Quantum Shard effect **/
var MiniMiner = Container.expand(function (parentMiner) {
var self = Container.call(this);
// Use the miner asset but scaled down.
@@ -66,9 +346,10 @@
self.miningDamage = parentMiner.miningDamage;
self.miningRate = parentMiner.miningRate;
self.currentTarget = null;
self.update = function () {
- if (self.currentTarget && self.currentTarget.parent) {
+ // Simple movement toward a target ore.
+ if (self.currentTarget) {
var tx = self.currentTarget.parent.x + self.currentTarget.x,
ty = self.currentTarget.parent.y + self.currentTarget.y;
var dx = tx - self.x,
dy = ty - self.y,
@@ -76,9 +357,11 @@
if (dist > 25) {
self.x += dx / dist * self.speed;
self.y += dy / dist * self.speed;
} else {
+ // Attack the ore and show pink, bold floating text offset lower.
self.currentTarget.health -= self.miningDamage;
+ // Offset the floating text (e.g., add extra Y offset)
showFloatingText(Math.round(self.miningDamage), 0xFF69B4);
if (self.currentTarget.health <= 0) {
self.currentTarget.cluster.notifyOreDestroyed(self.currentTarget);
self.currentTarget = null;
@@ -100,11 +383,8 @@
}
};
return self;
});
-/****
-* CLASSES
-****/
/** Ore – represents a single ore. **/
var Ore = Container.expand(function (type, cluster) {
var self = Container.call(this);
self.type = type;
@@ -161,10 +441,8 @@
gameState.tapCount++;
updateUI();
self.health -= actualDamage;
spawnMiningParticles(self, 2);
- // Always show blue floating text for ore tap
- showFloatingText(reward, 0x0000FF);
// Check for special ore triggers upon destruction.
if (self.health <= 0) {
var destroySound = LK.getSound('ore_destroy_' + self.type);
if (destroySound) {
@@ -180,8 +458,10 @@
if (self.type === "quantumshard" && !quantumShardActive) {
triggerQuantumShardEffect();
}
self.cluster.notifyOreDestroyed(self);
+ // Show floating text for ore tap (blue)
+ showFloatingText(reward, 0x0000FF);
}
};
// If the ore is one of the special types, add a pulsing glow.
if (["chronostone", "soulember", "quantumshard"].indexOf(type) >= 0) {
@@ -266,123 +546,67 @@
/****
* Initialize Game
****/
+/****
+* INITIALIZE GAME
+****/
var game = new LK.Game({
- backgroundColor: 0x000000
+ backgroundColor: 0x1a1a1a
});
/****
* Game Code
****/
-// Background transition function – fixed to work on every prestige
+// Helper function to get a valid cluster center position
+function getValidClusterCenter() {
+ // Define the UI boundaries or any restricted areas
+ var uiMargin = 200;
+ var minX = uiMargin;
+ var maxX = 2048 - uiMargin;
+ var minY = uiMargin;
+ var maxY = 2732 - uiMargin;
+ // Generate a random position within the valid area
+ var x = randomInt(minX, maxX);
+ var y = randomInt(minY, maxY);
+ return {
+ x: x,
+ y: y
+ };
+}
/****
-* SPECIAL EFFECTS FUNCTIONS
+* GLOBAL VARIABLES & SPECIAL EFFECT FLAGS
****/
-function handleBackgroundTransition() {
- var bgAssetId;
- if (gameState.prestigeCount >= 8) {
- bgAssetId = 'background_tier8';
- } else if (gameState.prestigeCount >= 5) {
- bgAssetId = 'background_tier5';
- } else if (gameState.prestigeCount >= 3) {
- bgAssetId = 'background_tier3';
- } else {
- bgAssetId = 'background';
- }
- // Remove any existing nextBackground from previous transitions.
- if (nextBackground && nextBackground.parent) {
- nextBackground.parent.removeChild(nextBackground);
- }
- // Create the new background off–screen (below)
- var newBg = LK.getAsset(bgAssetId, {
- anchorX: 0.5,
- anchorY: 0.5
- });
- newBg.x = 2048 / 2;
- newBg.y = 2732 + 2732 / 2;
- newBg.zIndex = -100;
- game.addChildAt(newBg, 0);
- nextBackground = newBg;
- // Use currentBackground as the old background; if not set, create one.
- var oldBg = currentBackground;
- if (!oldBg) {
- oldBg = LK.getAsset(bgAssetId, {
- anchorX: 0.5,
- anchorY: 0.5
- });
- oldBg.x = 2048 / 2;
- oldBg.y = 2732 / 2;
- oldBg.zIndex = -100;
- game.addChildAt(oldBg, 0);
- }
- var dur = 3000;
- // Animate old background sliding up (off–screen at the top)
- tween(oldBg, {
- y: -2732 / 2
- }, {
- duration: dur,
- onFinish: function onFinish() {
- if (oldBg && oldBg.parent) {
- oldBg.parent.removeChild(oldBg);
- }
- }
- });
- // Animate new background sliding in to center
- tween(newBg, {
- y: 2732 / 2
- }, {
- duration: dur,
- onFinish: function onFinish() {
- currentBackground = newBg;
- gamePaused = false;
- initialSpawn();
- }
- });
-}
-// (Other special effect functions like triggerChronostoneEffect, triggerSoulEmberEffect,
-// triggerQuantumShardEffect, triggerMeteorShowerEffect, etc. remain unchanged.)
-// …
/****
-* SPAWN FUNCTIONS
+* PLUGINS
****/
-function initialSpawn() {
- if (gamePaused) {
- return;
- }
- var allTypes = ['coal', 'iron', 'gold', 'diamond', 'sapphire', 'emerald', 'ruby'];
- allTypes.forEach(function (type, idx) {
- var t = idx + 1;
- if (t <= gameState.currentTier) {
- for (var i = 0; i < gameState.maxClustersPerType; i++) {
- maybeSpawnCluster(type);
- }
- }
- });
- maybeSpawnSpecialOres();
-}
/****
-* GLOBAL VARIABLES & SPECIAL EFFECT FLAGS
+* GAME-STATE & STATS
****/
-var clusters = [];
-var currentBackground = null;
-var nextBackground = null;
-var miner = null;
-var droneObjects = [];
-var droneSprites = [];
-var prestigeMainButton = null;
-var gamePaused = false;
+var statsTextObj = null; // will store the Text2 object for the stats
+// Special ore effect flags and timers (assuming 60 FPS)
var chronostoneActive = false;
+var chronostoneTimer = 0; // in frames (30 sec = 30*60)
+var chronostoneOverlay = null;
+var chronostoneTimerText = null;
+var chronostoneBannerShown = false;
+var soulEmberActive = false;
+var soulEmberOverlay = null;
+var soulEmberBannerShown = false;
+var soulEmberBoostCount = 0; // lasts for 10 ore mines
var quantumShardActive = false;
+var quantumShardTimer = 0; // 10 sec effect
+var quantumShardOverlay = null;
+var quantumShardBannerShown = false;
+var miniMiners = []; // array to hold mini miner instances
+var meteorShowerActive = false;
+var meteorShowerBannerShown = false;
+// For special ores that spawn singularly (instead of in clusters)
var specialOres = {
chronostone: null,
soulember: null,
quantumshard: null
};
-var miniMiners = []; // For quantum shard mini miners
-/****
-* GAME STATE & OTHER DATA
-****/
var gameState = {
money: 0,
pickaxeLevel: 1,
pickaxeBaseMultiplier: 1,
@@ -460,9 +684,9 @@
quantumshard: 0
}
};
/****
-* ACHIEVEMENTS
+* ACHIEVEMENTS
****/
var achievements = [{
id: 'first_mine',
name: 'First Mine',
@@ -489,9 +713,9 @@
return gameState.oreMined.coal >= 50;
}
}];
/****
-* ORE DATA (Even values)
+* ORE DATA (Even values)
****/
var oreData = {
coal: {
baseValue: 5,
@@ -635,9 +859,9 @@
}
});
}
/****
-* SPECIAL EFFECT FUNCTIONS
+* SPECIAL EFFECT FUNCTIONS
****/
// Helper: Display an event banner (bold, black text with outline) at the top.
function showEventBanner(text) {
var banner = new Text2(text, {
@@ -713,13 +937,15 @@
soulEmberOverlay.x = 2048 / 2;
soulEmberOverlay.y = 2732 / 2;
game.addChild(soulEmberOverlay);
}
+ // Deduct 10% of money and show floating text for the deduction.
var drain = gameState.money * 0.10;
gameState.money -= drain;
updateUI();
showFloatingText("-$" + Math.floor(drain).toLocaleString(), 0xFF0000);
soulEmberBoostCount = 10; // boost lasts for 10 ore mines
+ // Increase miner damage multiplier (for example purposes, increase by 50%)
gameState.pickaxeBaseMultiplier *= 1.5;
}
// Quantum Shard effect: split the miner into 5 mini miners for 10 seconds with blue overlay.
function triggerQuantumShardEffect() {
@@ -731,9 +957,10 @@
}
if (!quantumShardOverlay) {
quantumShardOverlay = LK.getAsset('quantumshard_overlay', {
anchorX: 0.5,
- anchorY: 0.5
+ anchorY: 0.5,
+ alpha: 0.5
});
quantumShardOverlay.x = 2048 / 2;
quantumShardOverlay.y = 2732 / 2;
game.addChild(quantumShardOverlay);
@@ -785,14 +1012,15 @@
});
aoe.x = target.x;
aoe.y = target.y;
game.addChild(aoe);
+ // Damage ores within 50px in each direction (100x100 area)
clusters.forEach(function (cluster) {
cluster.oreList.forEach(function (ore) {
var oreGlobalX = cluster.x + ore.x,
oreGlobalY = cluster.y + ore.y;
if (Math.abs(oreGlobalX - target.x) < 50 && Math.abs(oreGlobalY - target.y) < 50) {
- var damage = 100;
+ var damage = 100; // high damage value
ore.health -= damage;
showFloatingText("Meteor: " + damage, 0xFFFFFF);
if (ore.health <= 0) {
ore.cluster.notifyOreDestroyed(ore);
@@ -812,10 +1040,12 @@
}
});
}
/****
-* UI HELPER: Floating Text
+* UI HELPER: Floating Text
****/
+// Colors: green for miner hits (0x00FF00), blue for ore taps (0x0000FF), red for drone hits (0xFF0000)
+// (For mini miners, we’ll use pink (0xFF69B4) and offset lower.)
function showFloatingText(amount, color) {
var txt = new Text2("+" + amount, {
size: 40,
fill: color,
@@ -823,15 +1053,17 @@
strokeThickness: 4,
align: 'center',
fontWeight: 'bold'
});
+ // Adjust position based on type of hit:
var offsetX = (Math.random() - 0.5) * 50;
var offsetY = (Math.random() - 0.5) * 50;
if (color === 0xFF0000) {
offsetX += 300;
} else if (color === 0x0000FF) {
offsetX -= 300;
} else if (color === 0xFF69B4) {
+ // for mini miners, lower the text
offsetY += 50;
}
txt.x = moneyDisplay.x + moneyDisplay.width / 2 + offsetX;
txt.y = moneyDisplay.y + moneyDisplay.height + offsetY;
@@ -846,11 +1078,12 @@
}
});
}
/****
-* SPECIAL SPAWNING: Prevent special ores from spawning in clusters.
+* SPECIAL SPAWNING: Prevent special ores from spawning in clusters.
****/
function maybeSpawnCluster(type) {
+ // For special ores, do not spawn clusters.
if (type === "chronostone" || type === "soulember" || type === "quantumshard") {
return;
}
var typeList = ['coal', 'iron', 'gold', 'diamond', 'sapphire', 'emerald', 'ruby'];
@@ -867,8 +1100,9 @@
game.addChild(cluster);
clusters.push(cluster);
gameState.clusterCount[type]++;
}
+// For special ores, spawn them singularly.
function maybeSpawnSpecialOres() {
var specialTypes = ['chronostone', 'soulember', 'quantumshard'];
specialTypes.forEach(function (type) {
if (!specialOres[type]) {
@@ -892,9 +1126,9 @@
game.addChild(singleOre);
specialOres[type] = singleOre;
}
/****
-* PRESTIGE & BACKGROUND TRANSITION
+* PRESTIGE & BACKGROUND TRANSITION
****/
function getPrestigeRequirement() {
return 1e9 * Math.pow(2, gameState.prestigeCount);
}
@@ -994,11 +1228,463 @@
upg.level = 0;
upg.purchased = false;
});
}
+function handleBackgroundTransition() {
+ var bgAssetId;
+ if (gameState.prestigeCount >= 8) {
+ bgAssetId = 'background_tier8';
+ } else if (gameState.prestigeCount >= 5) {
+ bgAssetId = 'background_tier5';
+ } else if (gameState.prestigeCount >= 3) {
+ bgAssetId = 'background_tier3';
+ } else {
+ bgAssetId = 'background';
+ }
+ // Remove any existing nextBackground from previous transitions.
+ if (nextBackground && nextBackground.parent) {
+ nextBackground.parent.removeChild(nextBackground);
+ if (typeof nextBackground.destroy === "function") {
+ nextBackground.destroy();
+ }
+ }
+ // Create the new background off–screen at the bottom.
+ var newBg = LK.getAsset(bgAssetId, {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ newBg.x = 2048 / 2;
+ newBg.y = 2732 + 2732 / 2; // Position offscreen (below)
+ newBg.zIndex = -100;
+ game.addChildAt(newBg, 0);
+ nextBackground = newBg;
+ // Use currentBackground as the old background; if not set, create one.
+ var oldBg = currentBackground;
+ if (!oldBg) {
+ oldBg = LK.getAsset(bgAssetId, {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ oldBg.x = 2048 / 2;
+ oldBg.y = 2732 / 2;
+ oldBg.zIndex = -100;
+ game.addChildAt(oldBg, 0);
+ }
+ var dur = 3000;
+ // Animate the old background sliding upward (out of view).
+ tween(oldBg, {
+ y: -2732 / 2
+ }, {
+ duration: dur,
+ onFinish: function onFinish() {
+ if (oldBg && oldBg.parent) {
+ oldBg.parent.removeChild(oldBg);
+ if (typeof oldBg.destroy === "function") {
+ oldBg.destroy();
+ }
+ }
+ }
+ });
+ // Animate the new background sliding in to center.
+ tween(newBg, {
+ y: 2732 / 2
+ }, {
+ duration: dur,
+ onFinish: function onFinish() {
+ currentBackground = newBg;
+ gamePaused = false;
+ initialSpawn();
+ }
+ });
+}
+var clusters = [];
+var currentBackground = null;
+var nextBackground = null;
+var miner = null;
+var droneObjects = [];
+var droneSprites = [];
+var prestigeMainButton = null;
+var gamePaused = false;
/****
-* UI
+* SPAWN FUNCTIONS
****/
+function initialSpawn() {
+ if (gamePaused) {
+ return;
+ }
+ var allTypes = ['coal', 'iron', 'gold', 'diamond', 'sapphire', 'emerald', 'ruby'];
+ allTypes.forEach(function (type, idx) {
+ var t = idx + 1;
+ if (t <= gameState.currentTier) {
+ for (var i = 0; i < gameState.maxClustersPerType; i++) {
+ maybeSpawnCluster(type);
+ }
+ }
+ });
+ maybeSpawnSpecialOres();
+}
+function updateDroneObjects() {
+ while (droneObjects.length < gameState.droneLevel) {
+ var d = new Drone();
+ d.x = 200 + Math.random() * (2048 - 400);
+ d.y = 200 + Math.random() * (2732 - 400);
+ droneObjects.push(d);
+ game.addChild(d);
+ }
+}
+function updateDroneSprites() {
+ while (droneSprites.length < gameState.droneLevel) {
+ var drone = LK.getAsset('drone_asset', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ drone.x = 100 + droneSprites.length * 90;
+ drone.y = 200;
+ droneSprites.push(drone);
+ game.addChild(drone);
+ }
+}
+/****
+* UPGRADE DATA
+****/
+// (Upgrade data remains unchanged)
+var oreUpgrades = {
+ coal: [{
+ id: 'double_coal',
+ name: 'Double Coal Value',
+ cost: 100,
+ multi: true,
+ level: 0,
+ maxLevel: 20,
+ effect: 'Doubles Coal Value each purchase',
+ action: function action() {
+ this.level++;
+ gameState.oreMultipliers.coal *= 2;
+ this.cost *= 2;
+ }
+ }],
+ iron: [{
+ id: 'unlock_iron',
+ name: 'Unlock Iron Mining',
+ cost: 7000,
+ effect: 'Allows iron ore clusters to spawn',
+ purchased: false,
+ action: function action() {
+ if (gameState.currentTier < 2) {
+ gameState.currentTier = 2;
+ }
+ for (var i = 0; i < gameState.maxClustersPerType; i++) {
+ maybeSpawnCluster('iron');
+ }
+ }
+ }, {
+ id: 'double_iron',
+ name: 'Double Iron Value',
+ cost: 1000,
+ multi: true,
+ level: 0,
+ maxLevel: 20,
+ effect: 'Doubles Iron Value each purchase',
+ action: function action() {
+ this.level++;
+ gameState.oreMultipliers.iron *= 2;
+ this.cost *= 2;
+ }
+ }],
+ gold: [{
+ id: 'unlock_gold',
+ name: 'Unlock Gold Mining',
+ cost: 70000,
+ effect: 'Allows gold ore clusters to spawn',
+ purchased: false,
+ action: function action() {
+ if (gameState.currentTier < 3) {
+ gameState.currentTier = 3;
+ }
+ for (var i = 0; i < gameState.maxClustersPerType; i++) {
+ maybeSpawnCluster('gold');
+ }
+ }
+ }, {
+ id: 'double_gold',
+ name: 'Double Gold Value',
+ cost: 20000,
+ multi: true,
+ level: 0,
+ maxLevel: 20,
+ effect: 'Doubles Gold Value each purchase',
+ action: function action() {
+ this.level++;
+ gameState.oreMultipliers.gold *= 2;
+ this.cost *= 2;
+ }
+ }],
+ diamond: [{
+ id: 'unlock_diamond',
+ name: 'Unlock Diamond Mining',
+ cost: 280000,
+ effect: 'Allows diamond ore clusters to spawn',
+ purchased: false,
+ action: function action() {
+ if (gameState.currentTier < 4) {
+ gameState.currentTier = 4;
+ }
+ for (var i = 0; i < gameState.maxClustersPerType; i++) {
+ maybeSpawnCluster('diamond');
+ }
+ }
+ }, {
+ id: 'double_diamond',
+ name: 'Double Diamond Value',
+ cost: 50000,
+ multi: true,
+ level: 0,
+ maxLevel: 20,
+ effect: 'Doubles Diamond Value each purchase',
+ action: function action() {
+ this.level++;
+ gameState.oreMultipliers.diamond *= 2;
+ this.cost *= 2;
+ }
+ }],
+ sapphire: [{
+ id: 'unlock_sapphire',
+ name: 'Unlock Sapphire Mining',
+ cost: 1400000,
+ effect: 'Allows sapphire ore clusters to spawn',
+ purchased: false,
+ action: function action() {
+ if (gameState.currentTier < 5) {
+ gameState.currentTier = 5;
+ }
+ for (var i = 0; i < gameState.maxClustersPerType; i++) {
+ maybeSpawnCluster('sapphire');
+ }
+ }
+ }, {
+ id: 'double_sapphire',
+ name: 'Double Sapphire Value',
+ cost: 200000,
+ multi: true,
+ level: 0,
+ maxLevel: 20,
+ effect: 'Doubles Sapphire Value each purchase',
+ action: function action() {
+ this.level++;
+ gameState.oreMultipliers.sapphire *= 2;
+ this.cost *= 2;
+ }
+ }],
+ emerald: [{
+ id: 'unlock_emerald',
+ name: 'Unlock Emerald Mining',
+ cost: 7000000,
+ effect: 'Allows emerald ore clusters to spawn',
+ purchased: false,
+ action: function action() {
+ if (gameState.currentTier < 6) {
+ gameState.currentTier = 6;
+ }
+ for (var i = 0; i < gameState.maxClustersPerType; i++) {
+ maybeSpawnCluster('emerald');
+ }
+ }
+ }, {
+ id: 'double_emerald',
+ name: 'Double Emerald Value',
+ cost: 1000000,
+ multi: true,
+ level: 0,
+ maxLevel: 20,
+ effect: 'Doubles Emerald Value each purchase',
+ action: function action() {
+ this.level++;
+ gameState.oreMultipliers.emerald *= 2;
+ this.cost *= 2;
+ }
+ }],
+ ruby: [{
+ id: 'unlock_ruby',
+ name: 'Unlock Ruby Mining',
+ cost: 14000000,
+ effect: 'Allows ruby ore clusters to spawn',
+ purchased: false,
+ action: function action() {
+ if (gameState.currentTier < 7) {
+ gameState.currentTier = 7;
+ }
+ for (var i = 0; i < gameState.maxClustersPerType; i++) {
+ maybeSpawnCluster('ruby');
+ }
+ }
+ }, {
+ id: 'double_ruby',
+ name: 'Double Ruby Value',
+ cost: 2000000,
+ multi: true,
+ level: 0,
+ maxLevel: 20,
+ effect: 'Doubles Ruby Value each purchase',
+ action: function action() {
+ this.level++;
+ gameState.oreMultipliers.ruby *= 2;
+ this.cost *= 2;
+ }
+ }]
+};
+var generalUpgrades = [{
+ id: 'faster_respawn',
+ name: 'Quicker Respawn',
+ cost: 8000,
+ effect: 'Halves respawn time (min 500 ms)',
+ multi: true,
+ level: 0,
+ maxLevel: 3,
+ action: function action() {
+ gameState.respawnTime = Math.max(500, gameState.respawnTime / 2);
+ this.level++;
+ this.cost = Math.floor(this.cost * 2);
+ }
+}, {
+ id: 'cluster_up',
+ name: 'Cluster Growth',
+ cost: 1000,
+ effect: 'Increases cluster size range',
+ multi: true,
+ level: 0,
+ maxLevel: 5,
+ action: function action() {
+ if (gameState.clusterUpgradeTier < gameState.clusterConfigLevels.length - 1) {
+ gameState.clusterUpgradeTier++;
+ }
+ this.level++;
+ this.cost += 2000;
+ }
+}, {
+ id: 'pickaxe_buff',
+ name: 'Pickaxe DMG +20%',
+ cost: 20000,
+ effect: 'Increases your total pickaxe damage by 20%',
+ multi: true,
+ level: 0,
+ maxLevel: 20,
+ action: function action() {
+ this.level++;
+ gameState.pickaxeBaseMultiplier *= 1.2;
+ this.cost = Math.floor(this.cost * 2);
+ }
+}, {
+ id: 'tap_damage',
+ name: 'Tap Damage Upgrade',
+ cost: 5000,
+ effect: 'Increase tap damage by 50%',
+ multi: true,
+ level: 0,
+ maxLevel: 20,
+ action: function action() {
+ this.level++;
+ gameState.tapDamage *= 1.5;
+ this.cost = Math.floor(this.cost * 2);
+ }
+}, {
+ id: 'miner_speed',
+ name: 'Miner Swing Speed Upgrade',
+ cost: 20000,
+ effect: 'Increase miner swing speed (reduce cooldown by 10%)',
+ multi: true,
+ level: 0,
+ maxLevel: 20,
+ action: function action() {
+ this.level++;
+ miner.miningRate = Math.max(1, Math.floor(miner.miningRate * 0.9));
+ this.cost = Math.floor(this.cost * 2);
+ }
+}];
+var prestigeUpgrades = [{
+ id: 'pickaxe_plus_1',
+ name: 'Pickaxe Level +1',
+ cost: 3,
+ effect: 'Increases pickaxe damage by 1',
+ purchased: false,
+ action: function action() {
+ gameState.pickaxeLevel++;
+ }
+}, {
+ id: 'pickaxe_plus_2',
+ name: 'Pickaxe Speed +10%',
+ cost: 4,
+ effect: 'Reduces mining cooldown by 10%',
+ purchased: false,
+ action: function action() {
+ miner.miningRate = Math.floor(miner.miningRate * 0.90);
+ if (miner.miningRate < 1) {
+ miner.miningRate = 1;
+ }
+ }
+}, {
+ id: 'pickaxe_plus_3',
+ name: 'Pickaxe Bonus DMG +2',
+ cost: 6,
+ effect: 'Increases pickaxe damage by an additional 2',
+ purchased: false,
+ action: function action() {
+ gameState.pickaxeLevel += 2;
+ }
+}, {
+ id: 'pickaxe_plus_4',
+ name: 'Mega Pickaxe',
+ cost: 15,
+ effect: 'Increases pickaxe damage by an additional 5',
+ purchased: false,
+ action: function action() {
+ gameState.pickaxeLevel += 5;
+ }
+}];
+var prestigeDrones = [{
+ id: 'drone_speedup',
+ name: 'Drone Technology +1',
+ cost: 8,
+ effect: 'Increases Drone DPS by 50',
+ purchased: false,
+ action: function action() {
+ if (!gameState.droneLevel) {
+ gameState.droneLevel = 0;
+ }
+ gameState.droneLevel += 5;
+ }
+}, {
+ id: 'drone_overclock',
+ name: 'Drone Overclock',
+ cost: 12,
+ effect: 'Increases Drone DPS by 100',
+ purchased: false,
+ action: function action() {
+ gameState.droneLevel += 10;
+ }
+}];
+var droneUpgrades = [{
+ id: 'drone_level_1',
+ name: 'Buy Drones (Lv +1)',
+ cost: 5000,
+ effect: 'Each level adds +10 DPS',
+ purchased: false,
+ multi: true,
+ level: 0,
+ maxLevel: 20,
+ action: function action() {
+ if (!gameState.droneLevel) {
+ gameState.droneLevel = 0;
+ }
+ gameState.droneLevel++;
+ this.level++;
+ this.cost = Math.floor(this.cost * 1.5);
+ updateDroneObjects();
+ }
+}];
+/****
+* UI
+****/
+// Create the upgrade menu container (always on top).
var upgradeMenu = new Container();
upgradeMenu.zIndex = 10000;
var tooltip = new Text2('', {
size: 40,
@@ -1040,8 +1726,9 @@
upgradeMenu.parent.setChildIndex(upgradeMenu, upgradeMenu.parent.children.length - 1);
}
};
game.addChild(shopOpenButton);
+// Test money button (modified to give $5 TRILLION).
var addMoneyButton = LK.getAsset('test_money_button', {
anchorX: 0.5,
anchorY: 0.5
});
@@ -1052,9 +1739,9 @@
updateUI();
};
game.addChild(addMoneyButton);
/****
-* UPGRADE MODAL HELPER
+* UPGRADE MODAL HELPER
****/
function showUpgradeModal(upg, btn, callback) {
var modal = new Container();
var bg = LK.getAsset('upgrade_popup_bg', {
@@ -1122,9 +1809,9 @@
modal.destroy();
};
}
/****
-* PRESTIGE MODAL
+* PRESTIGE MODAL
****/
function showPrestigeModal() {
var modal = new Container();
var popup = LK.getAsset('prestige_popup', {
@@ -1179,9 +1866,9 @@
modal.destroy();
};
}
/****
-* MAIN UPGRADE MENU
+* MAIN UPGRADE MENU
****/
function createMainUpgradeMenu() {
upgradeMenu.removeChildren();
subUpgradeItemRefs = [];
@@ -1405,9 +2092,9 @@
}
return true;
}
/****
-* GAME LOOP
+* GAME LOOP
****/
var quantumSelectTimer = 0,
quantumSelectionActive = false;
game.update = function () {
@@ -1429,20 +2116,8 @@
ore.alpha = fraction;
}
});
});
- // Also update the health bars for special ores (SingleOre)
- for (var key in specialOres) {
- if (specialOres[key]) {
- var ore = specialOres[key].children[0];
- if (ore.health > 0) {
- var fraction = ore.health / ore.maxHealth;
- ore.healthBar.width = 120 * fraction;
- ore.healthBar.fill = interpolateColor(0xFF0000, 0x00FF00, fraction);
- ore.alpha = fraction;
- }
- }
- }
if (upgradeMenu.parent) {
subUpgradeItemRefs.forEach(function (ref) {
var upg = ref.upgrade;
var canBuy = canPurchaseUpgrade(ref.upgList, upg);
@@ -1450,10 +2125,18 @@
ref.textObj.style.fill = canBuy ? 0xFFFFFF : 0x666666;
}
});
}
+ // Update dynamic game stats if the stats menu is open.
if (statsTextObj) {
+ var oreTypes = ['coal', 'iron', 'gold', 'diamond', 'sapphire', 'emerald', 'ruby', 'chronostone', 'soulember', 'quantumshard'];
+ var oreStats = "";
+ oreTypes.forEach(function (type) {
+ var oreName = type.charAt(0).toUpperCase() + type.slice(1);
+ oreStats += oreName + " Mined: " + (gameState.oreMined[type] || 0) + "\n";
+ });
var newStatsText = "";
+ newStatsText += oreStats;
newStatsText += "Total Money Earned: $" + gameState.totalMoneyEarned.toLocaleString() + "\n";
var achievedCount = achievements.filter(function (a) {
return a.achieved;
}).length;
@@ -1473,8 +2156,9 @@
}
newStatsText += "Fully Upgraded Ore Upgrades: " + fullyUpgraded + "\n";
statsTextObj.setText(newStatsText);
}
+ // Update Chronostone effect timer and overlay.
if (chronostoneActive) {
chronostoneTimer--;
if (chronostoneTimerText) {
var secondsLeft = Math.ceil(chronostoneTimer / 60);
@@ -1497,8 +2181,9 @@
}
chronostoneBannerShown = false;
}
}
+ // Update Quantum Shard effect (mini miners).
if (quantumShardActive) {
quantumShardTimer--;
miniMiners.forEach(function (mini) {
mini.update();
@@ -1604,9 +2289,9 @@
}
}
}
/****
-* UI REFRESH & SAVE/LOAD
+* UI REFRESH & SAVE/LOAD
****/
function updateUI() {
moneyDisplay.setText("$" + Math.floor(gameState.money).toLocaleString());
moneyDisplay.x = 2048 / 2 - moneyDisplay.width / 2;
@@ -1619,9 +2304,9 @@
gameState = data;
updateUI();
};
/****
-* START GAME
+* START GAME
****/
function startGame() {
currentBackground = LK.getAsset('background', {
anchorX: 0.5,
@@ -1642,11 +2327,8 @@
game.pauseForQuantumSelection = function () {
quantumSelectionActive = true;
quantumSelectTimer = 0;
};
-/****
-* PRESTIGE MENUS & OTHER SUBMENUS
-****/
function createPrestigeMenu() {
upgradeMenu.removeChildren();
var menuBg = LK.getAsset('rectangle', {
width: 1800,
@@ -1762,8 +2444,9 @@
});
title.anchor.set(0.5);
container.addChild(title);
if (ach.target !== undefined) {
+ var currentProgress = ach.id === 'coal_miner' ? gameState.oreMined.coal : 0;
var progressBarBg = LK.getAsset('achievement_bar', {
width: 400,
height: 30,
color: 0x555555,
@@ -1772,9 +2455,8 @@
});
progressBarBg.x = -200;
progressBarBg.y = 50;
container.addChild(progressBarBg);
- var currentProgress = ach.id === 'coal_miner' ? gameState.oreMined.coal : 0;
var progressWidth = Math.min(currentProgress / ach.target * 400, 400);
var progressBarFg = LK.getAsset('rectangle', {
width: progressWidth,
height: 30,
@@ -1847,8 +2529,36 @@
titleText.anchor.set(0.5);
titleText.x = menuBg.x;
titleText.y = menuBg.y - 1000;
upgradeMenu.addChild(titleText);
+ var oreTypes = ['coal', 'iron', 'gold', 'diamond', 'sapphire', 'emerald', 'ruby', 'chronostone', 'soulember', 'quantumshard'];
+ var yStart = menuBg.y - 800,
+ spacing = 60;
+ oreTypes.forEach(function (type, index) {
+ var statContainer = new Container();
+ statContainer.x = menuBg.x - 600;
+ statContainer.y = yStart + index * spacing;
+ var oreAsset = LK.getAsset(type + '_ore', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ oreAsset.scale = 0.5;
+ oreAsset.x = 0;
+ oreAsset.y = 0;
+ statContainer.addChild(oreAsset);
+ var oreName = type.charAt(0).toUpperCase() + type.slice(1);
+ var countText = new Text2(oreName + " Mined: " + (gameState.oreMined[type] || 0), {
+ size: 40,
+ fill: 0x000000,
+ stroke: 0x000000,
+ strokeThickness: 4,
+ fontWeight: 'bold'
+ });
+ countText.x = 100;
+ countText.y = 0;
+ statContainer.addChild(countText);
+ upgradeMenu.addChild(statContainer);
+ });
var statsText = "";
statsText += "Total Money Earned: $" + gameState.totalMoneyEarned.toLocaleString() + "\n";
var achievedCount = achievements.filter(function (a) {
return a.achieved;
@@ -1867,19 +2577,18 @@
}
});
}
statsText += "Fully Upgraded Ore Upgrades: " + fullyUpgraded + "\n";
+ // Create the stats text object and store it in the global variable for dynamic updating.
statsTextObj = new Text2(statsText, {
size: 40,
- fill: 0xFFFFFF,
+ fill: 0x000000,
stroke: 0x000000,
strokeThickness: 4,
- fontWeight: 'bold',
- align: 'center'
+ fontWeight: 'bold'
});
- statsTextObj.anchor.set(0.5);
- statsTextObj.x = menuBg.x;
- statsTextObj.y = menuBg.y;
+ statsTextObj.x = menuBg.x + 200;
+ statsTextObj.y = menuBg.y - 800;
upgradeMenu.addChild(statsTextObj);
var backBtn = LK.getAsset('cancelButton', {
anchorX: 0.5,
anchorY: 0.5
@@ -1889,6 +2598,5 @@
backBtn.down = function () {
createMainUpgradeMenu();
};
upgradeMenu.addChild(backBtn);
-}
-var statsTextObj = null;
\ No newline at end of file
+}
\ No newline at end of file
drone_shot
Sound effect
mine_coal
Sound effect
mine_iron
Sound effect
mine_gold
Sound effect
mine_diamond
Sound effect
mine_sapphire
Sound effect
mine_emerald
Sound effect
mine_ruby
Sound effect
mine_chronostone
Sound effect
mine_quantumshard
Sound effect
ore_destroy_coal
Sound effect
ore_destroy_iron
Sound effect
ore_destroy_gold
Sound effect
ore_destroy_diamond
Sound effect
ore_destroy_sapphire
Sound effect
ore_destroy_emerald
Sound effect
ore_destroy_ruby
Sound effect
mine_coal_1
Sound effect
mine_coal_2
Sound effect
mine_coal_3
Sound effect
mine_diamond1
Sound effect
mine_diamond2
Sound effect
mine_diamond3
Sound effect
mine_emerald1
Sound effect
mine_emerald2
Sound effect
mine_emerald3
Sound effect
mine_gold1
Sound effect
mine_gold2
Sound effect
mine_gold3
Sound effect
mine_iron1
Sound effect
mine_iron2
Sound effect
mine_iron3
Sound effect
mine_ruby1
Sound effect
mine_ruby2
Sound effect
mine_ruby3
Sound effect
mine_sapphire1
Sound effect
mine_sapphire2
Sound effect
mine_sapphire3
Sound effect
song1
Music
song2
Music
song3
Music
song4
Music
song5
Music
song6
Music
song7
Music
song8
Music
song9
Music
song10
Music
song11
Music
song12
Music
song1a
Music
song1b
Music
song2a
Music
song2b
Music
song3a
Music
song3b
Music
song4a
Music
song4b
Music
song5a
Music
song5b
Music
song6a
Music
song6b
Music
song7a
Music
song7b
Music
song8a
Music
song8b
Music
song9a
Music
song9b
Music
song10a
Music
song10b
Music
song11a
Music
song11b
Music
song12a
Music
song12b
Music