User prompt
update with: // Find this line in hitContainer.down function where clam amount is incremented: upgrade.amount++; // Immediately after this line, add: console.log("Clam purchased, new amount:", upgrade.amount); // Then add the check code: var totalClams = UPGRADE_CONFIG.machines.basicClam.amount + UPGRADE_CONFIG.machines.advancedClam.amount + UPGRADE_CONFIG.machines.premiumClam.amount; console.log("Total clams now:", totalClams); // Direct update approach: if (totalClams >= 4 && key === 'basicClam') { console.log("Should set basic clam to SOLD OUT"); costText.setText("SOLD OUT"); costText.fill = 0x888888; // Gray color }
User prompt
update with: // After upgrading a clam and seeing totalClams >= 4: console.log("Forcing tab refresh for clams"); // Clear existing tab container while (tabContainers['clams'].children.length > 0) { tabContainers['clams'].children[0].destroy(); } // Recreate all upgrades for the tab if (tabColumns['clams'] && tabColumns['clams'].left) { tabColumns['clams'].left.forEach(function (upgrade, index) { createUpgradeText(upgrade[0], upgrade[1], index, true, 'clams'); }); } if (tabColumns['clams'] && tabColumns['clams'].right) { tabColumns['clams'].right.forEach(function (upgrade, index) { createUpgradeText(upgrade[0], upgrade[1], index, false, 'clams'); }); }
User prompt
Update with: if (category === 'machines' && upgrade.amount !== undefined) { if (upgrade.amount < (upgrade.maxAmount || 999)) { upgrade.amount++; game.bp -= cost; bpText.setText(formatBP(game.bp) + " BP"); costText.setText(getUpgradeCost(upgrade) + " BP"); // Add this line: refreshUpgradeTab('clams'); // Refresh entire clams tab if (category === 'machines') { updateClamVisuals(); } } }
User prompt
Update with: hitContainer.down = function() { var cost = getUpgradeCost(upgrade); // For machines, check clam limit first if (category === 'machines') { var totalClams = UPGRADE_CONFIG.machines.basicClam.amount + UPGRADE_CONFIG.machines.advancedClam.amount + UPGRADE_CONFIG.machines.premiumClam.amount; if (totalClams >= 4) { if (key === 'basicClam') { costText.setText("SOLD OUT"); costText.fill = 0x888888; return true; } // Only allow upgrades if we're replacing lower tier clams if (key === 'advancedClam' && UPGRADE_CONFIG.machines.basicClam.amount > 0) { // Existing upgrade logic... } else if (key === 'premiumClam' && (UPGRADE_CONFIG.machines.basicClam.amount > 0 || UPGRADE_CONFIG.machines.advancedClam.amount > 0)) { // Existing upgrade logic... } else { game.showError("Maximum of 4 clams reached!"); return true; } } } // Then check if player can afford it if (game.bp >= cost) { // Rest of existing purchase logic... } else { game.showError("Not enough BP!"); } return true; };
User prompt
Update with: function refreshUpgradeTab(tabName) { // Existing refresh code... if (tabName === 'clams') { var totalClams = UPGRADE_CONFIG.machines.basicClam.amount + UPGRADE_CONFIG.machines.advancedClam.amount + UPGRADE_CONFIG.machines.premiumClam.amount; if (totalClams >= 4) { // Find basic clam cost text and update it tabContainers[tabName].children.forEach(function(child) { if (child.text && child.text.includes("BP")) { var nameText = tabContainers[tabName].children.find(function(c) { return c.text === UPGRADE_CONFIG.machines.basicClam.name; }); if (nameText && child.y > nameText.y && child.y < nameText.y + 150) { child.setText("SOLD OUT"); child.fill = 0x888888; } } }); } } }
User prompt
Update with: function getUpgradeCost(upgrade) { if (upgrade.amount !== undefined) { // For clams, consider total clams when calculating cost if (upgrade.name.includes('Clam')) { var totalClams = UPGRADE_CONFIG.machines.basicClam.amount + UPGRADE_CONFIG.machines.advancedClam.amount + UPGRADE_CONFIG.machines.premiumClam.amount; return Math.floor(upgrade.baseCost * Math.pow(upgrade.costScale, totalClams)); } return Math.floor(upgrade.baseCost * Math.pow(upgrade.costScale, upgrade.amount)); } else { return Math.floor(upgrade.baseCost * Math.pow(upgrade.costScale, upgrade.currentLevel)); } }
User prompt
Update as needed: if (category === 'machines') { var totalClams = UPGRADE_CONFIG.machines.basicClam.amount + UPGRADE_CONFIG.machines.advancedClam.amount + UPGRADE_CONFIG.machines.premiumClam.amount; if (totalClams >= 4) { // Basic clam - just show sold out if (key === 'basicClam') { costText.setText("SOLD OUT"); costText.fill = 0x888888; return true; } // Advanced clam upgrade - can replace basic if (key === 'advancedClam' && UPGRADE_CONFIG.machines.basicClam.amount > 0) { if (game.bp >= cost) { UPGRADE_CONFIG.machines.basicClam.amount--; UPGRADE_CONFIG.machines.advancedClam.amount++; game.bp -= cost; bpText.setText(formatBP(game.bp) + " BP"); updateClamVisuals(); refreshUpgradeTab('clams'); } return true; } // Premium clam upgrade - can replace either basic or advanced if (key === 'premiumClam') { // First try to replace basic clam if (UPGRADE_CONFIG.machines.basicClam.amount > 0) { if (game.bp >= cost) { UPGRADE_CONFIG.machines.basicClam.amount--; UPGRADE_CONFIG.machines.premiumClam.amount++; game.bp -= cost; bpText.setText(formatBP(game.bp) + " BP"); updateClamVisuals(); refreshUpgradeTab('clams'); } return true; } // If no basic clams, try to replace advanced else if (UPGRADE_CONFIG.machines.advancedClam.amount > 0) { if (game.bp >= cost) { UPGRADE_CONFIG.machines.advancedClam.amount--; UPGRADE_CONFIG.machines.premiumClam.amount++; game.bp -= cost; bpText.setText(formatBP(game.bp) + " BP"); updateClamVisuals(); refreshUpgradeTab('clams'); } return true; } } game.showError("Maximum of 4 clams reached!"); return true; } // Normal purchase logic for when total clams < 4 if (game.bp >= cost) { upgrade.amount++; game.bp -= cost; bpText.setText(formatBP(game.bp) + " BP"); costText.setText(getUpgradeCost(upgrade) + " BP"); updateClamVisuals(); refreshUpgradeTab('clams'); } else { game.showError("Not enough BP!"); } return true; }
Code edit (1 edits merged)
Please save this source code
User prompt
update as needed with: hitContainer.down = function () { var cost = getUpgradeCost(upgrade); // Special handling for colors that are already purchased if (category === 'colors' && upgrade.currentLevel > 0) { // Toggle this color as active if (UPGRADE_CONFIG.gameSettings.activeColor === key) { // If already active, switch to auto UPGRADE_CONFIG.gameSettings.activeColor = "auto"; game.showMessage("Auto color mode"); } else { // Otherwise activate this color UPGRADE_CONFIG.gameSettings.activeColor = key; game.showMessage(upgrade.name + " activated"); } // Refresh the tab to update the text displays refreshUpgradeTab('colors'); return true; } // Regular upgrade purchase logic if (category === 'colors' && upgrade.requires) { var required = UPGRADE_CONFIG.colors[upgrade.requires]; if (required && required.currentLevel === 0) { game.showError("Unlock " + required.name + " first!"); return true; } } if (game.bp >= cost) { if (category === 'machines') { var totalClams = UPGRADE_CONFIG.machines.basicClam.amount + UPGRADE_CONFIG.machines.advancedClam.amount + UPGRADE_CONFIG.machines.premiumClam.amount; // Check if already at max clams if (totalClams >= 4) { if (key === 'basicClam') { updateCostText(category, key, "SOLD OUT", 0x888888); return true; // Add return here } // If trying to upgrade (e.g. basic to advanced) if (key === 'advancedClam' && UPGRADE_CONFIG.machines.basicClam.amount > 0) { // Replace a basic clam with advanced UPGRADE_CONFIG.machines.basicClam.amount--; upgrade.amount++; game.bp -= cost; bpText.setText(formatBP(game.bp) + " BP"); updateClamVisuals(); return true; } else if (key === 'premiumClam' && (UPGRADE_CONFIG.machines.basicClam.amount > 0 || UPGRADE_CONFIG.machines.advancedClam.amount > 0)) { // Replace lower tier clam with premium if (UPGRADE_CONFIG.machines.basicClam.amount > 0) { UPGRADE_CONFIG.machines.basicClam.amount--; } else { UPGRADE_CONFIG.machines.advancedClam.amount--; } upgrade.amount++; game.bp -= cost; bpText.setText(formatBP(game.bp) + " BP"); updateClamVisuals(); return true; } else { game.showError("Maximum of 4 clams reached!"); return true; } } } if (upgrade.amount !== undefined) { // For clams and decorations with amount if (upgrade.amount < (upgrade.maxAmount || 999)) { upgrade.amount++; game.bp -= cost; bpText.setText(formatBP(game.bp) + " BP"); updateCostText(category, key, getUpgradeCost(upgrade) + " BP", 0xFFFF00); // Update visuals if (category === 'machines') { updateClamVisuals(); } else if (category === 'decorations') { if (key === 'bubbleCoral') { updateCoralDecorations(); } else if (key === 'sunkenTreasures') { updateTreasureDecorations(); } } } } else if (upgrade.currentLevel < upgrade.maxLevel) { // For regular upgrades with levels upgrade.currentLevel++; game.bp -= cost; bpText.setText(formatBP(game.bp) + " BP"); // If this is a color upgrade, update the UI if (category === 'colors') { refreshUpgradeTab('colors'); return true; } // Update cost text if (upgrade.currentLevel >= upgrade.maxLevel) { updateCostText(category, key, "SOLD OUT", 0x888888); } else { updateCostText(category, key, getUpgradeCost(upgrade) + " BP", 0xFFFF00); } // Handle specific upgrade effects if (category === 'player') { if (key === 'lungCapacity') { var baseSize = UPGRADE_EFFECTS.lungCapacity.baseValue; var increasePercent = UPGRADE_EFFECTS.lungCapacity.incrementPercent; var multiplier = 1 + increasePercent / 100 * upgrade.currentLevel; game.maxBubbleSize = baseSize * multiplier; } else if (key === 'quickBreath') { game.growthRate = UPGRADE_EFFECTS.quickBreath.baseValue * (1 + UPGRADE_EFFECTS.quickBreath.incrementPercent / 100 * upgrade.currentLevel); } } } } else { game.showError("Not enough BP!"); } return true; };
Code edit (1 edits merged)
Please save this source code
User prompt
update with: function updateClamVisuals() { // Clear existing clams while (clamContainer.children.length) { clamContainer.children[0].destroy(); } // Total number of clams to display var totalClams = UPGRADE_CONFIG.machines.basicClam.amount + UPGRADE_CONFIG.machines.advancedClam.amount + UPGRADE_CONFIG.machines.premiumClam.amount; // Create array to hold exactly the right number of clams var clamTypes = new Array(totalClams); // Fill all positions with null initially for (var i = 0; i < clamTypes.length; i++) { clamTypes[i] = null; } // Fill with premium clams first (highest priority) var premiumCount = UPGRADE_CONFIG.machines.premiumClam.amount; for (var i = 0; i < premiumCount; i++) { if (i < clamTypes.length) { clamTypes[i] = 'premiumClam'; } } // Fill with advanced clams next var advancedCount = UPGRADE_CONFIG.machines.advancedClam.amount; for (var i = 0; i < advancedCount; i++) { if (i + premiumCount < clamTypes.length) { clamTypes[i + premiumCount] = 'advancedClam'; } } // Fill remaining slots with basic clams var basicCount = UPGRADE_CONFIG.machines.basicClam.amount; for (var i = 0; i < basicCount; i++) { if (i + premiumCount + advancedCount < clamTypes.length) { clamTypes[i + premiumCount + advancedCount] = 'basicClam'; } } // Place clams game.clamSpawnPoints = []; clamTypes.forEach(function (type, i) { if (!type) return; // Skip null entries var isRight = i % 2 === 1; var baseX = isRight ? rightStart : leftStart; var direction = isRight ? -1 : 1; var position = Math.floor(i / 2); var x = baseX + direction * position * spacing; var sprite = LK.getAsset(type, { anchorX: 0.5, anchorY: 1, x: x, y: y, scaleX: isRight ? -0.5 : 0.5, // Flip right-side clams scaleY: 0.5 }); // Store spawn point for this clam game.clamSpawnPoints.push({ x: x + (isRight ? -75 : 75), // 25% from edge y: y - 50, // Slightly above clam type: type, isRight: isRight }); clamContainer.addChild(sprite); }); console.log("After visual update - Clam types: " + clamTypes.join(", ")); }
User prompt
Please fix the bug: 'ReferenceError: leftStart is not defined' in or related to this line: 'var baseX = isRight ? rightStart : leftStart;' Line Number: 1647
User prompt
update as needed with: function updateClamVisuals() { // Clear existing clams while (clamContainer.children.length) { clamContainer.children[0].destroy(); } // Define positioning variables (these were likely defined elsewhere) var leftStart = game.width * 0.1; var rightStart = game.width * 0.9; var spacing = 250; var y = game.height - 100; // Total number of clams to display var totalClams = UPGRADE_CONFIG.machines.basicClam.amount + UPGRADE_CONFIG.machines.advancedClam.amount + UPGRADE_CONFIG.machines.premiumClam.amount; // Create array to hold exactly the right number of clams var clamTypes = new Array(totalClams); // Fill all positions with null initially for (var i = 0; i < clamTypes.length; i++) { clamTypes[i] = null; } // Fill with premium clams first (highest priority) var premiumCount = UPGRADE_CONFIG.machines.premiumClam.amount; for (var i = 0; i < premiumCount; i++) { if (i < clamTypes.length) { clamTypes[i] = 'premiumClam'; } } // Fill with advanced clams next var advancedCount = UPGRADE_CONFIG.machines.advancedClam.amount; for (var i = 0; i < advancedCount; i++) { if (i + premiumCount < clamTypes.length) { clamTypes[i + premiumCount] = 'advancedClam'; } } // Fill remaining slots with basic clams var basicCount = UPGRADE_CONFIG.machines.basicClam.amount; for (var i = 0; i < basicCount; i++) { if (i + premiumCount + advancedCount < clamTypes.length) { clamTypes[i + premiumCount + advancedCount] = 'basicClam'; } } // Place clams game.clamSpawnPoints = []; clamTypes.forEach(function (type, i) { if (!type) return; // Skip null entries var isRight = i % 2 === 1; var baseX = isRight ? rightStart : leftStart; var direction = isRight ? -1 : 1; var position = Math.floor(i / 2); var x = baseX + direction * position * spacing; var sprite = LK.getAsset(type, { anchorX: 0.5, anchorY: 1, x: x, y: y, scaleX: isRight ? -0.5 : 0.5, // Flip right-side clams scaleY: 0.5 }); // Store spawn point for this clam game.clamSpawnPoints.push({ x: x + (isRight ? -75 : 75), // 25% from edge y: y - 50, // Slightly above clam type: type, isRight: isRight }); clamContainer.addChild(sprite); }); console.log("After visual update - Clam types: " + clamTypes.join(", ")); }
User prompt
update with: // Advanced clam - replace exactly one basic clam if (key === 'advancedClam') { if (UPGRADE_CONFIG.machines.basicClam.amount > 0) { // Replace one basic clam UPGRADE_CONFIG.machines.basicClam.amount--; upgrade.amount++; game.bp -= cost; // Update BP text bpText.setText(formatBP(game.bp) + " BP"); // Force a complete refresh of the clams tab refreshUpgradeTab('clams'); // Update visual representation of clams updateClamVisuals(); return true; } else { game.showError("No basic clams to upgrade!"); return true; } }
Code edit (2 edits merged)
Please save this source code
User prompt
Update with: // When creating tab text initially, set the color based on whether it's the current tab var tabText = new Text2(tab.charAt(0).toUpperCase() + tab.slice(1), { size: 80, fill: tab === currentTab ? 0xFFFF00 : 0xFFFFFF, // Yellow if active, white otherwise stroke: 0x000000, strokeThickness: 3, font: "Impact" }); // Store reference to the text object tabButtons[tab].textRef = tabText; // Then in the tab.down function, update to also change text color: tabButton.down = function () { if (tab !== currentTab) { // Update tab appearance Object.keys(tabButtons).forEach(function (t) { if (tabButtons[t]) { tabButtons[t].alpha = t === tab ? 1.0 : 0.7; // Change text color if (tabButtons[t].textRef) { tabButtons[t].textRef.fill = t === tab ? 0xFFFF00 : 0xFFFFFF; } } }); // Hide current tab content, show new tab content if (tabContainers[currentTab]) { tabContainers[currentTab].visible = false; } if (tabContainers[tab]) { tabContainers[tab].visible = true; } // Update current tab currentTab = tab; } return true; };
Code edit (1 edits merged)
Please save this source code
User prompt
Update with: var tabText = new Text2(tab.charAt(0).toUpperCase() + tab.slice(1), { size: 80, fill: tab === currentTab ? 0xFFFF00 : 0xFFFFFF, // Set initial color based on current tab stroke: 0x000000, strokeThickness: 3, font: "Impact" }); tabText.anchor = { x: 0.5, y: 0.5 }; tabText.x = tabButton.x; tabText.y = tabHeight / 2; // Store reference to text tabTextRefs[tab] = tabText;
User prompt
Update with: tabButton.down = function () { if (tab !== currentTab) { // Update tab appearance Object.keys(tabButtons).forEach(function (t) { if (tabButtons[t]) { tabButtons[t].alpha = t === tab ? 1.0 : 0.7; } }); // Update text colors Object.keys(tabTextRefs).forEach(function (t) { tabTextRefs[t].fill = t === tab ? 0xFFFF00 : 0xFFFFFF; }); // Hide current tab content, show new tab content if (tabContainers[currentTab]) { tabContainers[currentTab].visible = false; } if (tabContainers[tab]) { tabContainers[tab].visible = true; } // Update current tab currentTab = tab; } return true; };
User prompt
Update with: var activeTabIndicator = LK.getAsset('blower', { width: tabWidth, height: 10, // Small bar at bottom of tab color: 0xFFFF00, // Yellow indicator alpha: 1.0 }); // Position at the bottom of the current tab activeTabIndicator.x = tabButtons[currentTab].x - tabWidth/2; activeTabIndicator.y = tabHeight - 5; // Add to tab container tabsContainer.addChild(activeTabIndicator);
User prompt
Please fix the bug: 'undefined is not an object (evaluating 'tabButtons[currentTab].x')' in or related to this line: 'activeTabIndicator.x = tabButtons[currentTab].x - tabWidth / 2;' Line Number: 1026
User prompt
Update as needed with: // Add this code after the forEach closing bracket but before adding the tabsContainer to menuContainer // Create active tab indicator var activeTabIndicator = LK.getAsset('blower', { width: tabWidth, height: 10, // Small bar at bottom of tab color: 0xFFFF00, // Yellow indicator alpha: 1.0 }); // Position at the bottom of the current tab activeTabIndicator.x = tabButtons[currentTab].x - tabWidth/2; activeTabIndicator.y = tabHeight - 5; // Add to tab container tabsContainer.addChild(activeTabIndicator); // THEN FIND AND REPLACE ALL THE tabButton.down FUNCTIONS // Inside the menuTabs.forEach loop, find the tabButton.down function and replace it with this: tabButton.down = function () { if (tab !== currentTab) { // Update tab appearance Object.keys(tabButtons).forEach(function (t) { if (tabButtons[t]) { tabButtons[t].alpha = t === tab ? 1.0 : 0.7; } }); // Move the indicator to the new tab activeTabIndicator.x = tabButtons[tab].x - tabWidth/2; // Hide current tab content, show new tab content if (tabContainers[currentTab]) { tabContainers[currentTab].visible = false; } if (tabContainers[tab]) { tabContainers[tab].visible = true; } // Update current tab currentTab = tab; } return true; };
User prompt
Update with: tabButton.down = function () { if (tab !== currentTab) { // Update tab appearance Object.keys(tabButtons).forEach(function (t) { if (tabButtons[t]) { tabButtons[t].alpha = t === tab ? 1.0 : 0.7; } }); // Move the indicator to the new tab instead of creating a new one activeTabIndicator.x = tabButton.x - tabWidth/2; // Hide current tab content, show new tab content if (tabContainers[currentTab]) { tabContainers[currentTab].visible = false; } if (tabContainers[tab]) { tabContainers[tab].visible = true; } // Update current tab currentTab = tab; } return true; };
User prompt
Update with: // AFTER CREATING ACTIVE TAB INDICATOR, STORE IT IN GAME OBJECT FOR REFERENCE // Store indicator in game object to access it globally game.activeTabIndicator = activeTabIndicator; // THEN REPLACE ALL tabButton.down FUNCTIONS WITH THIS tabButton.down = function () { if (tab !== currentTab) { // Update tab appearance Object.keys(tabButtons).forEach(function (t) { if (tabButtons[t]) { tabButtons[t].alpha = t === tab ? 1.0 : 0.7; } }); // Remove old indicator from display if (game.activeTabIndicator) { tabsContainer.removeChild(game.activeTabIndicator); } // Create new indicator for current tab var newIndicator = LK.getAsset('blower', { width: tabWidth, height: 10, color: 0xFFFF00, alpha: 1.0 }); // Position at the bottom of this tab newIndicator.x = tabButton.x - tabWidth/2; newIndicator.y = tabHeight - 5; // Add to container and store reference tabsContainer.addChild(newIndicator); game.activeTabIndicator = newIndicator; // Hide current tab content, show new tab content if (tabContainers[currentTab]) { tabContainers[currentTab].visible = false; } if (tabContainers[tab]) { tabContainers[tab].visible = true; } // Update current tab currentTab = tab; } return true; };
User prompt
Update just this: game.tabIndicators = []; game.tabIndicators.push(activeTabIndicator);
===================================================================
--- original.js
+++ change.js
@@ -524,633 +524,56 @@
/****
* Game Code
****/
-if (typeof UPGRADE_CONFIG === 'undefined') {
- var UPGRADE_CONFIG = {};
-}
-if (!UPGRADE_CONFIG.gameSettings) {
- UPGRADE_CONFIG.gameSettings = {
- activeColor: "auto" // Default to automatic progression
- };
-}
-// Add function to get current active color
-function getActiveColorKey() {
- if (UPGRADE_CONFIG.gameSettings.activeColor === "auto") {
- // Find highest unlocked color in order of value
- var colorKeys = ["prismaticBubbles", "rainbowBubbles", "silverBubbles", "crimsonBubbles", "goldBubbles", "tealBubbles", "pinkBubbles", "orangeBubbles", "greenBubbles", "purpleBubbles", "blueBubbles"];
- for (var i = 0; i < colorKeys.length; i++) {
- if (UPGRADE_CONFIG.colors[colorKeys[i]].currentLevel > 0) {
- return colorKeys[i];
- }
- }
- }
- return UPGRADE_CONFIG.gameSettings.activeColor;
-}
-// Add a function to set active color
-function setActiveColor(colorKey) {
- if (colorKey === "auto" || UPGRADE_CONFIG.colors[colorKey].currentLevel > 0) {
- UPGRADE_CONFIG.gameSettings.activeColor = colorKey;
- // Update visual indicator in UI
- updateColorSelectionUI();
- } else {
- game.showError("Unlock this color first!");
- }
-}
-function getTreasureBonusMultiplier(x, y) {
- if (!game.treasureZones || game.treasureZones.length === 0) {
- return 1.0; // No bonus if no treasures
- }
- // Start with no bonus
- var totalBonus = 0;
- // Check each treasure zone
- game.treasureZones.forEach(function (zone) {
- var dx = x - zone.x;
- var dy = y - zone.y;
- var distance = Math.sqrt(dx * dx + dy * dy);
- // If bubble is in zone, add 50% bonus
- if (distance <= zone.radius) {
- totalBonus += 0.5; // +50% per overlapping zone as specified
- }
- });
- // Return multiplier (1.0 = no bonus, 1.5 = one zone, 2.0 = two zones, etc.)
- return 1.0 + totalBonus;
-}
-// Function to update treasure decorations
-function updateTreasureDecorations() {
- // Clear existing treasures
- while (treasureContainer.children.length) {
- treasureContainer.children[0].destroy();
- }
- // Clear zone tracking
- game.treasureZones = [];
- var treasureCount = UPGRADE_CONFIG.decorations.sunkenTreasures.amount;
- if (treasureCount <= 0) {
- return;
- }
- // Available treasure types
- var treasureTypes = ['treasure1', 'treasure2', 'treasure3'];
- // Position treasures at specific spots in the bottom half of screen
- var positions = [
- // Left side
- {
- x: game.width * 0.25,
- y: game.height * 0.65
- },
- // Right side
- {
- x: game.width * 0.75,
- y: game.height * 0.65
- },
- // Middle bottom
- {
- x: game.width * 0.5,
- y: game.height * 0.8
- }];
- // Place treasures at predetermined spots
- for (var i = 0; i < treasureCount; i++) {
- // Don't exceed available positions
- if (i >= positions.length) {
- break;
- }
- // Choose treasure type based on position
- var treasureType = treasureTypes[i % treasureTypes.length];
- var pos = positions[i];
- // Create circular zone indicator
- var zoneRadius = game.width * 0.15;
- var zoneIndicator = LK.getAsset('blower', {
- width: zoneRadius * 2,
- height: zoneRadius * 2,
- shape: 'circle',
- // Specify circle shape
- color: 0xFFFFFF,
- alpha: 0.15,
- anchorX: 0.5,
- anchorY: 0.5,
- x: pos.x,
- y: pos.y
- });
- // Add zone to tracking for bonus calculation
- game.treasureZones.push({
- id: 'treasure_' + i,
- x: pos.x,
- y: pos.y,
- radius: zoneRadius
- });
- // Create treasure sprite on top of zone
- var treasure = LK.getAsset(treasureType, {
- anchorX: 0.5,
- anchorY: 0.5,
- x: pos.x,
- y: pos.y,
- scaleX: 1.8,
- scaleY: 1.8,
- alpha: 0.9
- });
- // Add zone first (so it's behind treasure)
- treasureContainer.addChild(zoneIndicator);
- treasureContainer.addChild(treasure);
- }
-}
-function updateCoralBubbles() {
- if (UPGRADE_CONFIG.decorations.bubbleCoral.amount <= 0) {
- return;
- }
- coralContainer.children.forEach(function (coral) {
- // 5% chance per second to spawn bubble (0.083% per frame at 60fps)
- if (Math.random() < 0.00083 || LK.ticks - coral.lastBubbleTime > 600) {
- // Force spawn after 10 seconds
- coral.lastBubbleTime = LK.ticks;
- // Calculate bubble size based on player's max size
- var bubbleSize = game.maxBubbleSize * (0.5 + Math.random() * 0.3);
- // Spawn position slightly above coral
- var bubbleX = coral.x + (Math.random() * 30 - 15);
- var bubbleY = coral.y - coral.height * 0.3;
- var bubble = spawnBubble(bubbleX, bubbleY, bubbleSize, 0, false);
- if (bubble) {
- // Set moderate upward velocity
- bubble.verticalVelocity = -(2 + Math.random() * 3);
- bubble.driftX = Math.random() * 2 - 1;
- }
- }
- });
-}
-function updateCoralDecorations() {
- // Clear existing corals
- while (coralContainer.children.length) {
- coralContainer.children[0].destroy();
- }
- // Position corals along bottom of screen
- var coralCount = UPGRADE_CONFIG.decorations.bubbleCoral.amount;
- if (coralCount <= 0) {
- return;
- }
- // Available coral types
- var coralTypes = ['coral1', 'coral2', 'coral3', 'coral4'];
- // Space corals evenly along bottom
- var spacing = game.width / (coralCount + 1);
- for (var i = 0; i < coralCount; i++) {
- // Choose random coral type
- var coralType = coralTypes[Math.floor(Math.random() * coralTypes.length)];
- // Create coral sprite
- var coral = LK.getAsset(coralType, {
- anchorX: 0.5,
- anchorY: 1,
- x: spacing * (i + 1),
- y: game.height - 20,
- // Slightly above bottom
- scaleX: 1.5 + Math.random() * 0.5,
- scaleY: 1.5 + Math.random() * 0.5
- });
- // Store last bubble spawn time
- coral.lastBubbleTime = 0;
- coralContainer.addChild(coral);
- }
-}
-function refreshUpgradeTab(tabName) {
- // Clear all children from the tab container
- while (tabContainers[tabName].children.length > 0) {
- tabContainers[tabName].children[0].destroy();
- }
- // Recreate all upgrades for the tab
- if (tabColumns[tabName] && tabColumns[tabName].left) {
- tabColumns[tabName].left.forEach(function (upgrade, index) {
- createUpgradeText(upgrade[0], upgrade[1], index, true, tabName);
- });
- }
- if (tabColumns[tabName] && tabColumns[tabName].right) {
- tabColumns[tabName].right.forEach(function (upgrade, index) {
- createUpgradeText(upgrade[0], upgrade[1], index, false, tabName);
- });
- }
- // Add this at the end of the function:
- if (tabName === 'colors') {
- var activeColorKey = getActiveColorKey();
- tabColumns[tabName].left.concat(tabColumns[tabName].right).forEach(function (upgrade) {
- var category = upgrade[0];
- var key = upgrade[1];
- var upgradeConfig = UPGRADE_CONFIG[category][key];
- if (upgradeConfig.currentLevel > 0) {
- // Find the corresponding cost text for this upgrade
- tabContainers[tabName].children.forEach(function (child) {
- // Identify the cost text by its position below the name
- if (child.text && child.y > 0) {
- var nameText = tabContainers[tabName].children.find(function (c) {
- return c.text === upgradeConfig.name;
- });
- if (nameText && child.y > nameText.y && child.y < nameText.y + 150) {
- // Check if this color is active
- if (activeColorKey === key || UPGRADE_CONFIG.gameSettings.activeColor === "auto" && key === activeColorKey) {
- child.setText("ACTIVE");
- child.fill = 0x00FF00; // Green
- } else if (category === 'colors' && upgradeConfig.currentLevel === 1) {
- // If this is the first color purchased or auto is selected with no active colors
- if (UPGRADE_CONFIG.gameSettings.activeColor === "auto" || !UPGRADE_CONFIG.colors[UPGRADE_CONFIG.gameSettings.activeColor] || UPGRADE_CONFIG.colors[UPGRADE_CONFIG.gameSettings.activeColor].currentLevel === 0) {
- UPGRADE_CONFIG.gameSettings.activeColor = key;
- game.showMessage(upgradeConfig.name + " activated");
- }
- } else if (category === 'colors' && upgradeConfig.currentLevel >= upgradeConfig.maxLevel) {
- // Create "SOLD OUT" text for maxed out color upgrades
- child.setText("SOLD OUT");
- child.fill = 0x888888; // Gray
- } else {
- var cost = getUpgradeCost(upgradeConfig);
- child.setText(cost + " BP");
- child.fill = 0xFFFF00; // Yellow
- }
- }
- }
- });
- }
- });
- } else if (tabName === 'clams') {
- var totalClams = UPGRADE_CONFIG.machines.basicClam.amount + UPGRADE_CONFIG.machines.advancedClam.amount + UPGRADE_CONFIG.machines.premiumClam.amount;
- // Check if we've reached max clams
- if (totalClams >= 4) {
- // Find all basic clam upgrade texts and update them
- tabContainers[tabName].children.forEach(function (child) {
- if (child.text && (child.text.includes("BP") || child.text === "SOLD OUT")) {
- // Find the name text for basic clam
- var nameText = tabContainers[tabName].children.find(function (c) {
- return c.text === UPGRADE_CONFIG.machines.basicClam.name;
- });
- // If this cost text is below the basic clam name text
- if (nameText && child.y > nameText.y && child.y < nameText.y + 150) {
- child.setText("SOLD OUT");
- child.fill = 0x888888; // Gray color
- }
- }
- });
- }
- }
-}
-game.twinBubbles = [];
-game.treasureZones = [];
-// Define column assignments for each tab
-var tabColumns = {
- bubbles: {
- left: [['player', 'lungCapacity'], ['player', 'quickBreath'], ['player', 'bubbleRefinement'], ['player', 'twinBubbles']],
- right: [['player', 'autoPop'], ['player', 'sizeVariance'], ['player', 'bubbleBreath']]
- },
- clams: {
- left: [['machines', 'basicClam'], ['machines', 'advancedClam'], ['machines', 'premiumClam']],
- right: [['machine', 'bubbleDurability'], ['machine', 'autoBubbleSpeed'], ['machine', 'bubbleQuality']]
- },
- colors: {
- left: [['colors', 'blueBubbles'], ['colors', 'purpleBubbles'], ['colors', 'greenBubbles'], ['colors', 'orangeBubbles'], ['colors', 'pinkBubbles']],
- right: [['colors', 'tealBubbles'], ['colors', 'goldBubbles'], ['colors', 'crimsonBubbles'], ['colors', 'silverBubbles'], ['colors', 'rainbowBubbles'], ['colors', 'prismaticBubbles']]
- },
- decorations: {
- left: [['decorations', 'bubbleCoral']],
- right: [['decorations', 'sunkenTreasures']]
- }
-};
-var UPGRADE_EFFECTS = {
- lungCapacity: {
- baseValue: 160,
- // Base max bubble size
- incrementPercent: 25 // +25% per level
- },
- quickBreath: {
- baseValue: 1.6,
- // Base growth rate
- incrementPercent: 25 // +25% per level
- },
- autoBubbleSpeed: {
- decrementPercent: 10 // -10% production time per level
- },
- bubbleDurability: {
- extraSplits: 1 // +1 split per level
- },
- autoPop: {
- timeReduction: 0.8 // Reduces lifetime by 20% per level
- }
-};
-function _slicedToArray3(r, e) {
- return _arrayWithHoles3(r) || _iterableToArrayLimit3(r, e) || _unsupportedIterableToArray3(r, e) || _nonIterableRest3();
-}
-function _nonIterableRest3() {
- throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
-}
-function _unsupportedIterableToArray3(r, a) {
- if (r) {
- if ("string" == typeof r) {
- return _arrayLikeToArray3(r, a);
- }
- var t = {}.toString.call(r).slice(8, -1);
- return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray3(r, a) : void 0;
- }
-}
-function _arrayLikeToArray3(r, a) {
- (null == a || a > r.length) && (a = r.length);
- for (var e = 0, n = Array(a); e < a; e++) {
- n[e] = r[e];
- }
- return n;
-}
-function _iterableToArrayLimit3(r, l) {
- var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
- if (null != t) {
- var e,
- n,
- i,
- u,
- a = [],
- f = !0,
- o = !1;
- try {
- if (i = (t = t.call(r)).next, 0 === l) {
- if (Object(t) !== t) {
- return;
- }
- f = !1;
- } else {
- for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0) {
- ;
- }
- }
- } catch (r) {
- o = !0, n = r;
- } finally {
- try {
- if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) {
- return;
- }
- } finally {
- if (o) {
- throw n;
- }
- }
- }
- return a;
- }
-}
-function _arrayWithHoles3(r) {
- if (Array.isArray(r)) {
- return r;
- }
-}
-function getUpgradeCost(upgrade) {
- if (upgrade.amount !== undefined) {
- // For clams, consider total clams when calculating cost
- if (upgrade.name.includes('Clam')) {
- var totalClams = UPGRADE_CONFIG.machines.basicClam.amount + UPGRADE_CONFIG.machines.advancedClam.amount + UPGRADE_CONFIG.machines.premiumClam.amount;
- return Math.floor(upgrade.baseCost * Math.pow(upgrade.costScale, totalClams));
- }
- return Math.floor(upgrade.baseCost * Math.pow(upgrade.costScale, upgrade.amount));
- } else {
- // For regular upgrades
- return Math.floor(upgrade.baseCost * Math.pow(upgrade.costScale, upgrade.currentLevel));
- }
-}
-function _slicedToArray2(r, e) {
- return _arrayWithHoles2(r) || _iterableToArrayLimit2(r, e) || _unsupportedIterableToArray2(r, e) || _nonIterableRest2();
-}
-function _nonIterableRest2() {
- throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
-}
-function _unsupportedIterableToArray2(r, a) {
- if (r) {
- if ("string" == typeof r) {
- return _arrayLikeToArray2(r, a);
- }
- var t = {}.toString.call(r).slice(8, -1);
- return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray2(r, a) : void 0;
- }
-}
-function _arrayLikeToArray2(r, a) {
- (null == a || a > r.length) && (a = r.length);
- for (var e = 0, n = Array(a); e < a; e++) {
- n[e] = r[e];
- }
- return n;
-}
-function _iterableToArrayLimit2(r, l) {
- var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
- if (null != t) {
- var e,
- n,
- i,
- u,
- a = [],
- f = !0,
- o = !1;
- try {
- if (i = (t = t.call(r)).next, 0 === l) {
- if (Object(t) !== t) {
- return;
- }
- f = !1;
- } else {
- for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0) {
- ;
- }
- }
- } catch (r) {
- o = !0, n = r;
- } finally {
- try {
- if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) {
- return;
- }
- } finally {
- if (o) {
- throw n;
- }
- }
- }
- return a;
- }
-}
-function _arrayWithHoles2(r) {
- if (Array.isArray(r)) {
- return r;
- }
-}
-function updateClams() {
- if (!game.clamSpawnPoints) {
- return;
- }
- game.clamSpawnPoints.forEach(function (spawnPoint) {
- var config = UPGRADE_CONFIG.machines[spawnPoint.type];
- // Calculate production time with speed upgrade
- var baseTime = config.production * 150; // Convert to frames and further increase base time
- var speedMultiplier = Math.pow(1 - UPGRADE_EFFECTS.autoBubbleSpeed.decrementPercent / 100, UPGRADE_CONFIG.machine.autoBubbleSpeed.currentLevel);
- var adjustedTime = Math.max(1, Math.floor(baseTime * speedMultiplier));
- var qualityLevel = UPGRADE_CONFIG.machine.bubbleQuality.currentLevel;
- if (qualityLevel > 0) {
- // -10% production rate per level
- adjustedTime = Math.floor(adjustedTime * (1 + 0.1 * qualityLevel));
- }
- if (LK.ticks % adjustedTime === 0) {
- // Find first available bubble in pool
- var bubble = game.bubblePool.find(function (b) {
- return !b.visible;
- });
- if (bubble && game.activeBubbles.length < game.MAX_BUBBLES) {
- bubble.activate(spawnPoint.x, spawnPoint.y, config.bubbleSize, false // not player blown
- );
- bubble.fromClam = true;
- if (UPGRADE_CONFIG.player.sizeVariance.currentLevel > 0) {
- var variance = UPGRADE_CONFIG.player.sizeVariance.currentLevel;
- var minIncrease = 0.1 * variance; // +10% per level to min size
- var maxIncrease = 0.15 * variance; // +15% per level to max size
- // Apply size variance
- var sizeMultiplier = 1 - minIncrease + Math.random() * (minIncrease + maxIncrease);
- bubble.size *= sizeMultiplier;
- }
- // Set initial velocities for clam bubbles
- bubble.verticalVelocity = 0;
- bubble.driftX = (spawnPoint.isRight ? -1 : 1) * (Math.random() * 1.5 + 2);
- game.activeBubbles.push(bubble);
- }
- }
- });
-}
-function _slicedToArray(r, e) {
- return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest();
-}
-function _nonIterableRest() {
- throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
-}
-function _unsupportedIterableToArray(r, a) {
- if (r) {
- if ("string" == typeof r) {
- return _arrayLikeToArray(r, a);
- }
- var t = {}.toString.call(r).slice(8, -1);
- return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0;
- }
-}
-function _arrayLikeToArray(r, a) {
- (null == a || a > r.length) && (a = r.length);
- for (var e = 0, n = Array(a); e < a; e++) {
- n[e] = r[e];
- }
- return n;
-}
-function _iterableToArrayLimit(r, l) {
- var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
- if (null != t) {
- var e,
- n,
- i,
- u,
- a = [],
- f = !0,
- o = !1;
- try {
- if (i = (t = t.call(r)).next, 0 === l) {
- if (Object(t) !== t) {
- return;
- }
- f = !1;
- } else {
- for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0) {
- ;
- }
- }
- } catch (r) {
- o = !0, n = r;
- } finally {
- try {
- if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) {
- return;
- }
- } finally {
- if (o) {
- throw n;
- }
- }
- }
- return a;
- }
-}
-function _arrayWithHoles(r) {
- if (Array.isArray(r)) {
- return r;
- }
-}
-var background = LK.getAsset('background', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: game.width / 2,
- y: game.height / 2
-});
-game.addChild(background);
-// Add coral container here
-var coralContainer = new Container();
-game.addChild(coralContainer);
-// Reposition in display list
-game.setChildIndex(coralContainer, 1);
-var treasureContainer = new Container();
-// Add after coralContainer but before clams for proper layering
-game.addChild(treasureContainer);
-game.setChildIndex(treasureContainer, 2);
-var clamContainer = new Container();
-game.addChild(clamContainer);
-var playerMask = new pufferMask();
-game.addChild(playerMask);
var UPGRADE_CONFIG = {
gameSettings: {
activeColor: "auto" // Default to automatic progression (highest unlocked)
},
player: {
lungCapacity: {
name: "Lung Capacity",
baseCost: 100,
- // About 1-2 max bubbles
costScale: 3.0,
- // Steeper scaling
maxLevel: 10,
currentLevel: 0
},
quickBreath: {
name: "Quick Breath",
baseCost: 100,
- // 2-3 max bubbles
costScale: 3.0,
- // Steeper scaling
maxLevel: 10,
currentLevel: 0
},
autoPop: {
- // Moved here from machine section
name: "Fish Friends",
- // Updated name
baseCost: 400,
- // Changed from 1000
costScale: 3,
maxLevel: 6,
- // Changed from 5
currentLevel: 0
},
bubbleRefinement: {
- // New upgrade
name: "Bubble Refinement",
baseCost: 2500,
costScale: 2.5,
maxLevel: 5,
currentLevel: 0
},
twinBubbles: {
- // New upgrade
name: "Twin Bubbles",
baseCost: 5000,
costScale: 2.3,
maxLevel: 3,
currentLevel: 0
},
sizeVariance: {
- // New upgrade
name: "Size Variance",
baseCost: 4000,
costScale: 1.8,
maxLevel: 5,
currentLevel: 0
},
bubbleBreath: {
- // New upgrade
name: "Bubble Breath",
baseCost: 12000,
costScale: 2.2,
maxLevel: 4,
@@ -1160,19 +583,16 @@
machines: {
basicClam: {
name: "Basic Clam",
baseCost: 300,
- // 6-7 max bubbles
costScale: 2,
- // Slightly steeper scaling
amount: 0,
production: 3,
bubbleSize: 80
},
advancedClam: {
name: "Advanced Clam",
baseCost: 3000,
- // Requires running basic clams for a while
costScale: 3.0,
amount: 0,
production: 2,
bubbleSize: 100,
@@ -1180,9 +600,8 @@
},
premiumClam: {
name: "Premium Clam",
baseCost: 20000,
- // True end-game content
costScale: 3,
amount: 0,
production: 1,
bubbleSize: 150,
@@ -1193,9 +612,8 @@
bubbleDurability: {
name: "Bubble Splitting",
baseCost: 500,
costScale: 5,
- // Significant scaling
maxLevel: 3,
currentLevel: 0
},
autoBubbleSpeed: {
@@ -1205,18 +623,16 @@
maxLevel: 8,
currentLevel: 0
},
bubbleQuality: {
- // New upgrade
name: "Bubble Quality",
baseCost: 3000,
costScale: 2.2,
maxLevel: 5,
currentLevel: 0
}
},
colors: {
- // New section
blueBubbles: {
name: "Blue Bubbles",
baseCost: 1000,
costScale: 1.0,
@@ -1324,9 +740,8 @@
multiplier: 1.8
}
},
decorations: {
- // New section
bubbleCoral: {
name: "Bubble Coral",
baseCost: 10000,
costScale: 2.0,
@@ -1341,26 +756,142 @@
maxAmount: 3
}
}
};
+// Initialize upgrade registry for UI elements
+game.upgradeRegistry = {};
+var background = LK.getAsset('background', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: game.width / 2,
+ y: game.height / 2
+});
+game.addChild(background);
+// Add coral container
+var coralContainer = new Container();
+game.addChild(coralContainer);
+game.setChildIndex(coralContainer, 1);
+// Add treasure container
+var treasureContainer = new Container();
+game.addChild(treasureContainer);
+game.setChildIndex(treasureContainer, 2);
+// Add clam container
+var clamContainer = new Container();
+game.addChild(clamContainer);
+// Add player mask
+var playerMask = new pufferMask();
+game.addChild(playerMask);
+var UPGRADE_EFFECTS = {
+ lungCapacity: {
+ baseValue: 160,
+ incrementPercent: 25
+ },
+ quickBreath: {
+ baseValue: 1.6,
+ incrementPercent: 25
+ },
+ autoBubbleSpeed: {
+ decrementPercent: 10
+ },
+ bubbleDurability: {
+ extraSplits: 1
+ },
+ autoPop: {
+ timeReduction: 0.8
+ }
+};
+// Define column assignments for each tab
+var tabColumns = {
+ bubbles: {
+ left: [['player', 'lungCapacity'], ['player', 'quickBreath'], ['player', 'bubbleRefinement'], ['player', 'twinBubbles']],
+ right: [['player', 'autoPop'], ['player', 'sizeVariance'], ['player', 'bubbleBreath']]
+ },
+ clams: {
+ left: [['machines', 'basicClam'], ['machines', 'advancedClam'], ['machines', 'premiumClam']],
+ right: [['machine', 'bubbleDurability'], ['machine', 'autoBubbleSpeed'], ['machine', 'bubbleQuality']]
+ },
+ colors: {
+ left: [['colors', 'blueBubbles'], ['colors', 'purpleBubbles'], ['colors', 'greenBubbles'], ['colors', 'orangeBubbles'], ['colors', 'pinkBubbles']],
+ right: [['colors', 'tealBubbles'], ['colors', 'goldBubbles'], ['colors', 'crimsonBubbles'], ['colors', 'silverBubbles'], ['colors', 'rainbowBubbles'], ['colors', 'prismaticBubbles']]
+ },
+ decorations: {
+ left: [['decorations', 'bubbleCoral']],
+ right: [['decorations', 'sunkenTreasures']]
+ }
+};
+function getUpgradeCost(upgrade) {
+ if (upgrade.amount !== undefined) {
+ // For clams and decorations
+ return Math.floor(upgrade.baseCost * Math.pow(upgrade.costScale, upgrade.amount));
+ } else {
+ // For regular upgrades
+ return Math.floor(upgrade.baseCost * Math.pow(upgrade.costScale, upgrade.currentLevel));
+ }
+}
+function getActiveColorKey() {
+ if (UPGRADE_CONFIG.gameSettings.activeColor === "auto") {
+ // Find highest unlocked color in order of value
+ var colorKeys = ["prismaticBubbles", "rainbowBubbles", "silverBubbles", "crimsonBubbles", "goldBubbles", "tealBubbles", "pinkBubbles", "orangeBubbles", "greenBubbles", "purpleBubbles", "blueBubbles"];
+ for (var i = 0; i < colorKeys.length; i++) {
+ if (UPGRADE_CONFIG.colors[colorKeys[i]].currentLevel > 0) {
+ return colorKeys[i];
+ }
+ }
+ }
+ return UPGRADE_CONFIG.gameSettings.activeColor;
+}
+function setActiveColor(colorKey) {
+ if (colorKey === "auto" || UPGRADE_CONFIG.colors[colorKey].currentLevel > 0) {
+ UPGRADE_CONFIG.gameSettings.activeColor = colorKey;
+ // Update visual indicator in UI
+ updateColorSelectionUI();
+ } else {
+ game.showError("Unlock this color first!");
+ }
+}
+function getTreasureBonusMultiplier(x, y) {
+ if (!game.treasureZones || game.treasureZones.length === 0) {
+ return 1.0; // No bonus if no treasures
+ }
+ // Start with no bonus
+ var totalBonus = 0;
+ // Check each treasure zone
+ game.treasureZones.forEach(function (zone) {
+ var dx = x - zone.x;
+ var dy = y - zone.y;
+ var distance = Math.sqrt(dx * dx + dy * dy);
+ // If bubble is in zone, add 50% bonus
+ if (distance <= zone.radius) {
+ totalBonus += 0.5; // +50% per overlapping zone
+ }
+ });
+ // Return multiplier (1.0 = no bonus, 1.5 = one zone, 2.0 = two zones, etc.)
+ return 1.0 + totalBonus;
+}
+function formatBP(value) {
+ var units = ['', 'K', 'M', 'B', 'T'];
+ var unitIndex = 0;
+ while (value >= 1000 && unitIndex < units.length - 1) {
+ value /= 1000;
+ unitIndex++;
+ }
+ return Math.floor(value * 10) / 10 + units[unitIndex];
+}
game.showError = function (message) {
var errorText = new Text2(message, {
size: 120,
fill: 0xFF0000,
stroke: 0x000000,
strokeThickness: 5,
font: "Impact"
});
- // Set the anchor point to center the text
errorText.anchor = {
x: 0.5,
y: 0.5
};
- // Position at the center of the screen
errorText.x = game.width / 2;
errorText.y = game.height / 2;
game.addChild(errorText);
- // Animate the text
tween(errorText, {
alpha: 0,
y: errorText.y - 50
}, {
@@ -1377,18 +908,15 @@
stroke: 0x000000,
strokeThickness: 3,
font: "Impact"
});
- // Set the anchor point to center the text
messageText.anchor = {
x: 0.5,
y: 0.5
};
- // Position at the center of the screen
messageText.x = game.width / 2;
messageText.y = game.height / 2;
game.addChild(messageText);
- // Animate the text
tween(messageText, {
alpha: 0,
y: messageText.y - 30
}, {
@@ -1400,33 +928,9 @@
};
var currentTab = 'bubbles'; // Default tab
var menuTabs = ['bubbles', 'clams', 'colors', 'decorations'];
var tabButtons = {}; // Will hold references to tab buttons
-// Create upgrade menu elements
-// Menu tab (handle)
-// First position the panel relative to container at y=0
-// Menu panel should be below the tab in the container
-var menuTab = LK.getAsset('upgradetab', {
- anchorX: 0.5,
- anchorY: 1,
- // Change to bottom anchor
- y: 0,
- // Will be at container's position
- scaleX: 3,
- scaleY: 0.8,
- alpha: 0.9
-});
-var menuPanel = LK.getAsset('upgradetab', {
- anchorX: 0.5,
- anchorY: 0,
- y: -570,
- alpha: 0.9,
- scaleX: 2048 / 200,
- // Use the width of the asset directly
- scaleY: game.height * 0.4 / 100.3
-});
-// Initialize menu structure
-// Initialize menu container at the right position
+// Create menu container at the right position
var menuContainer = new Container();
menuContainer.x = game.width / 2;
menuContainer.y = game.height; // Position at bottom
var menuPanel = LK.getAsset('upgradetab', {
@@ -1447,9 +951,9 @@
});
// Add panel first (so it's behind tab)
menuContainer.addChild(menuPanel);
menuContainer.addChild(menuTab);
-// Menu text setup - should be good as is
+// Menu text
var menuText = new Text2("Upgrades", {
size: 90,
fill: 0xFFFFFF,
stroke: 0x000000,
@@ -1464,25 +968,21 @@
menuText.y = -menuTab.height / 2; // Position relative to container bottom
menuContainer.addChild(menuText);
// Add to game
game.addChild(menuContainer);
-// Add this after the menuPanel is created but before upgradeTexts are created
-// Create text container AFTER panel scaling
+// Create text container
var menuTextContainer = new Container();
menuContainer.addChild(menuTextContainer);
+// Create tab containers
var tabContainers = {};
menuTabs.forEach(function (tab) {
var contentContainer = new Container();
contentContainer.visible = tab === currentTab;
tabContainers[tab] = contentContainer;
menuTextContainer.addChild(contentContainer);
});
-// Create text container AFTER panel scaling
-var menuTextContainer = new Container();
-menuContainer.addChild(menuTextContainer);
-// Create tab container (only visible when menu is open)
+// Create tabs container (only visible when menu is open)
var tabsContainer = new Container();
-// Position tabsContainer at the bottom of the panel
tabsContainer.x = menuPanel.width * menuPanel.scaleX / 2 - 850; // Center horizontally
tabsContainer.y = 0;
menuContainer.addChild(tabsContainer);
// Define tab dimensions
@@ -1493,21 +993,16 @@
// Create tab button
var tabButton = LK.getAsset('upgradetab', {
anchorX: 0.5,
anchorY: 0,
- // Anchor to top
- // Position evenly across panel width
x: -menuPanel.width * menuPanel.scaleX / 2 + (index + 0.5) * tabWidth,
y: 0,
- // Start at the container's position
scaleX: tabWidth / 200,
scaleY: tabHeight / 299,
- // Updated for new height
alpha: tab === currentTab ? 1.0 : 0.7
});
- // Add hit detection to the tab button
+ // Add hit detection
tabButton.down = function () {
- // Only do something if this isn't already the current tab
if (tab !== currentTab) {
// Update tab appearance
Object.keys(tabButtons).forEach(function (t) {
if (tabButtons[t]) {
@@ -1523,22 +1018,18 @@
}
// Update current tab
currentTab = tab;
}
- // Return true to indicate the event was handled
return true;
};
// Store reference to the button
tabButtons[tab] = tabButton;
// Add text to tab
var tabText = new Text2(tab.charAt(0).toUpperCase() + tab.slice(1), {
- // Capitalize first letter
size: 80,
- // Increased from 50
fill: 0xFFFFFF,
stroke: 0x000000,
strokeThickness: 3,
- // Slightly thicker for larger text
font: "Impact"
});
tabText.anchor = {
x: 0.5,
@@ -1549,50 +1040,111 @@
// Add to container
tabsContainer.addChild(tabButton);
tabsContainer.addChild(tabText);
});
-// Function to switch between tabs
-function switchTab(newTab) {
- // Hide old tab content, show new tab content
- tabContainers[currentTab].visible = false;
- tabContainers[newTab].visible = true;
- // Update tab button appearance
- tabButtons[currentTab].alpha = 0.7;
- tabButtons[newTab].alpha = 1.0;
- currentTab = newTab;
-}
-// Add upgrade texts to text container instead of panel
-var upgradeTexts = [];
-var startY = 150;
-var upgradeSpacing = 250;
-var columnWidth = 1024;
-// Create arrays to hold upgrade categories in desired order
-var leftColumnUpgrades = [['player', 'lungCapacity'], ['player', 'quickBreath'], ['player', 'autoPop']];
-var rightColumnUpgrades = [['machines', 'basicClam'], ['machines', 'advancedClam'], ['machines', 'premiumClam'], ['machine', 'bubbleDurability'], ['machine', 'autoBubbleSpeed']];
-// Function to determine which tab an upgrade belongs to
-function getTabForUpgrade(category, key) {
- if (category === 'player') {
- return 'bubbles';
+// Move the entire text container to align with panel
+menuTextContainer.y = 0;
+menuTextContainer.x = 0;
+// Initialize menu state
+var menuOpen = false;
+var menuTargetY = game.height;
+// Create BP display text
+var bpText = new Text2("0 BP", {
+ size: 120,
+ fill: 0xFFFFFF,
+ stroke: 0x33caf8,
+ strokeThickness: 4,
+ font: "Impact",
+ fontWeight: "bold"
+});
+bpText.anchor.set(1, 0);
+bpText.x = game.width - 20;
+bpText.y = 20;
+game.addChild(bpText);
+// Initialize BP tracking
+game.bp = 0;
+game.combo = 0;
+game.lastPopTime = 0;
+game.COMBO_WINDOW = 60; // 1 second in frames
+game.addBP = function (points, x, y, isAutoPop) {
+ var currentTime = LK.ticks;
+ // Only update combo if it's not an auto-pop
+ if (!isAutoPop) {
+ if (currentTime - game.lastPopTime < game.COMBO_WINDOW) {
+ game.combo++;
+ points *= 1 + game.combo * 0.1; // 10% bonus per combo
+ } else {
+ game.combo = 0;
+ }
+ game.lastPopTime = currentTime;
}
- if (category === 'machines' || category === 'machine') {
- return 'clams';
+ // Ensure points is at least 1
+ points = Math.max(1, Math.floor(points));
+ game.bp += points;
+ bpText.setText(formatBP(game.bp) + " BP");
+ // Set size and color based on point value
+ var textSize = 96;
+ var textColor = 0xFFFF00; // Default yellow
+ if (points > 100) {
+ textSize = 120;
+ textColor = 0xFF0000; // Red for >100
+ } else if (points > 50) {
+ textSize = 108;
+ textColor = 0xFFA500; // Orange for 51-100
}
- if (category === 'colors') {
- return 'colors';
+ // Always show point text
+ var pointText = new Text2("+" + points, {
+ size: textSize,
+ fill: textColor,
+ font: "Impact",
+ fontWeight: 'bold'
+ });
+ pointText.anchorX = 0.5;
+ pointText.anchorY = 0.5;
+ pointText.x = x;
+ pointText.y = y;
+ game.addChild(pointText);
+ tween(pointText, {
+ y: pointText.y - 100,
+ alpha: 0
+ }, {
+ duration: 1200,
+ onFinish: function onFinish() {
+ pointText.destroy();
+ }
+ });
+ // Only show combo text if it's a manual pop and we have a combo
+ if (!isAutoPop && game.combo > 0) {
+ var comboText = new Text2("x" + (game.combo + 1), {
+ size: 96,
+ fill: 0xFFA500,
+ stroke: 0x000000,
+ strokeThickness: 4,
+ fontWeight: 'bold'
+ });
+ comboText.anchorX = 0.5;
+ comboText.anchorY = 0;
+ comboText.x = game.width / 2;
+ comboText.y = 20;
+ game.addChild(comboText);
+ tween(comboText, {
+ alpha: 0
+ }, {
+ duration: 500,
+ onFinish: function onFinish() {
+ comboText.destroy();
+ }
+ });
}
- if (category === 'decorations') {
- return 'decorations';
- }
- return 'bubbles'; // Default
-}
-// Function to create upgrade text
+};
+// Function to create upgrade text (MODIFIED with Registry)
function createUpgradeText(category, key, index, isLeftColumn, tab) {
var upgrade = UPGRADE_CONFIG[category][key];
if (!upgrade) {
return;
- } // Skip if upgrade doesn't exist
- var xOffset = isLeftColumn ? -750 : 200; // Changed from -550 and 100
- var yPos = startY + index * upgradeSpacing + 120; // Added 120 to move everything down
+ }
+ var xOffset = isLeftColumn ? -750 : 200;
+ var yPos = startY + index * upgradeSpacing + 120;
// Create hit container
var hitContainer = new Container();
var hitArea = LK.getAsset('blower', {
width: 400,
@@ -1616,143 +1168,30 @@
nameText.x = xOffset;
nameText.y = yPos;
// Create cost text
var cost = getUpgradeCost(upgrade);
- var costText;
- if (category === 'machines' && key === 'basicClam') {
- var totalClams = UPGRADE_CONFIG.machines.basicClam.amount + UPGRADE_CONFIG.machines.advancedClam.amount + UPGRADE_CONFIG.machines.premiumClam.amount;
- if (totalClams >= 4) {
- costText = new Text2("SOLD OUT", {
- size: 96,
- fill: 0x888888,
- // Gray color
- stroke: 0x000000,
- strokeThickness: 2,
- font: "Impact"
- });
- }
- }
- // For colors, check active state first before any other states
- if (category === 'colors' && upgrade.currentLevel > 0) {
- var activeColorKey = getActiveColorKey();
- if (key === activeColorKey || UPGRADE_CONFIG.gameSettings.activeColor === "auto" && key === activeColorKey) {
- // Active color - green "ACTIVE" text
- costText = new Text2("ACTIVE", {
- size: 96,
- fill: 0x00FF00,
- // Green color for active
- stroke: 0x000000,
- strokeThickness: 2,
- font: "Impact"
- });
- } else if (upgrade.currentLevel >= upgrade.maxLevel) {
- // Maxed out color - gray "SOLD OUT" text
- costText = new Text2("SOLD OUT", {
- size: 96,
- fill: 0x888888,
- // Gray color
- stroke: 0x000000,
- strokeThickness: 2,
- font: "Impact"
- });
- } else {
- // Purchased but not active or maxed - yellow cost text
- costText = new Text2(cost + " BP", {
- size: 96,
- fill: 0xFFFF00,
- stroke: 0x000000,
- strokeThickness: 2,
- font: "Impact"
- });
- }
- } else if (category === 'colors' && upgrade.requires) {
- var required = UPGRADE_CONFIG.colors[upgrade.requires];
- if (required && required.currentLevel === 0) {
- // Create "LOCKED" text for locked upgrades
- costText = new Text2("LOCKED", {
- size: 96,
- fill: 0x888888,
- stroke: 0x000000,
- strokeThickness: 2,
- font: "Impact"
- });
- } else {
- // Normal cost text
- costText = new Text2(cost + " BP", {
- size: 96,
- fill: 0xFFFF00,
- stroke: 0x000000,
- strokeThickness: 2,
- font: "Impact"
- });
- }
- } else {
- // Normal cost text for non-color upgrades
- costText = new Text2(cost + " BP", {
- size: 96,
- fill: 0xFFFF00,
- stroke: 0x000000,
- strokeThickness: 2,
- font: "Impact"
- });
- }
+ var costText = new Text2(cost + " BP", {
+ size: 96,
+ fill: 0xFFFF00,
+ stroke: 0x000000,
+ strokeThickness: 2,
+ font: "Impact"
+ });
costText.x = xOffset;
costText.y = yPos + 100;
+ // Register the UI elements
+ if (!game.upgradeRegistry[category]) {
+ game.upgradeRegistry[category] = {};
+ }
+ game.upgradeRegistry[category][key] = {
+ nameText: nameText,
+ costText: costText,
+ hitContainer: hitContainer,
+ tab: tab
+ };
// Add click handler
hitContainer.down = function () {
var cost = getUpgradeCost(upgrade);
- // For machines, check clam limit first
- if (category === 'machines') {
- var totalClams = UPGRADE_CONFIG.machines.basicClam.amount + UPGRADE_CONFIG.machines.advancedClam.amount + UPGRADE_CONFIG.machines.premiumClam.amount;
- if (totalClams >= 4) {
- if (key === 'basicClam') {
- costText.setText("SOLD OUT");
- costText.fill = 0x888888;
- return true;
- }
- // Advanced clam upgrade - can replace basic
- if (key === 'advancedClam' && UPGRADE_CONFIG.machines.basicClam.amount > 0) {
- if (game.bp >= cost) {
- UPGRADE_CONFIG.machines.basicClam.amount--;
- UPGRADE_CONFIG.machines.advancedClam.amount++;
- game.bp -= cost;
- bpText.setText(formatBP(game.bp) + " BP");
- updateClamVisuals();
- refreshUpgradeTab('clams');
- }
- return true;
- } else if (key === 'premiumClam') {
- // First try to replace basic clam
- if (UPGRADE_CONFIG.machines.basicClam.amount > 0) {
- if (game.bp >= cost) {
- UPGRADE_CONFIG.machines.basicClam.amount--;
- UPGRADE_CONFIG.machines.premiumClam.amount++;
- game.bp -= cost;
- bpText.setText(formatBP(game.bp) + " BP");
- updateClamVisuals();
- refreshUpgradeTab('clams');
- }
- return true;
- }
- // If no basic clams, try to replace advanced
- else if (UPGRADE_CONFIG.machines.advancedClam.amount > 0) {
- if (game.bp >= cost) {
- UPGRADE_CONFIG.machines.advancedClam.amount--;
- UPGRADE_CONFIG.machines.premiumClam.amount++;
- game.bp -= cost;
- bpText.setText(formatBP(game.bp) + " BP");
- updateClamVisuals();
- refreshUpgradeTab('clams');
- }
- return true;
- }
- } else {
- game.showError("Maximum of 4 clams reached!");
- return true;
- }
- }
- }
- var child = costText; // Define 'child' as 'costText' to fix ReferenceError
// Special handling for colors that are already purchased
if (category === 'colors' && upgrade.currentLevel > 0) {
// Toggle this color as active
if (UPGRADE_CONFIG.gameSettings.activeColor === key) {
@@ -1767,9 +1206,9 @@
// Refresh the tab to update the text displays
refreshUpgradeTab('colors');
return true;
}
- // Regular upgrade purchase logic follows...
+ // Regular upgrade purchase logic
if (category === 'colors' && upgrade.requires) {
var required = UPGRADE_CONFIG.colors[upgrade.requires];
if (required && required.currentLevel === 0) {
game.showError("Unlock " + required.name + " first!");
@@ -1781,10 +1220,9 @@
var totalClams = UPGRADE_CONFIG.machines.basicClam.amount + UPGRADE_CONFIG.machines.advancedClam.amount + UPGRADE_CONFIG.machines.premiumClam.amount;
// Check if already at max clams
if (totalClams >= 4) {
if (key === 'basicClam') {
- child.setText("SOLD OUT");
- child.fill = 0x888888; // Gray color
+ updateCostText(category, key, "SOLD OUT", 0x888888);
}
// If trying to upgrade (e.g. basic to advanced)
if (key === 'advancedClam' && UPGRADE_CONFIG.machines.basicClam.amount > 0) {
// Replace a basic clam with advanced
@@ -1815,83 +1253,37 @@
if (upgrade.amount !== undefined) {
// For clams and decorations with amount
if (upgrade.amount < (upgrade.maxAmount || 999)) {
upgrade.amount++;
- console.log("Clam purchased, new amount:", upgrade.amount);
- var totalClams = UPGRADE_CONFIG.machines.basicClam.amount + UPGRADE_CONFIG.machines.advancedClam.amount + UPGRADE_CONFIG.machines.premiumClam.amount;
- console.log("Total clams now:", totalClams);
- if (totalClams >= 4 && key === 'basicClam') {
- console.log("Should set basic clam to SOLD OUT");
- costText.setText("SOLD OUT");
- costText.fill = 0x888888; // Gray color
- console.log("Forcing tab refresh for clams");
- // Clear existing tab container
- while (tabContainers['clams'].children.length > 0) {
- tabContainers['clams'].children[0].destroy();
- }
- // Recreate all upgrades for the tab
- if (tabColumns['clams'] && tabColumns['clams'].left) {
- tabColumns['clams'].left.forEach(function (upgrade, index) {
- createUpgradeText(upgrade[0], upgrade[1], index, true, 'clams');
- });
- }
- if (tabColumns['clams'] && tabColumns['clams'].right) {
- tabColumns['clams'].right.forEach(function (upgrade, index) {
- createUpgradeText(upgrade[0], upgrade[1], index, false, 'clams');
- });
- }
- }
game.bp -= cost;
- if (category === 'machines') {
- var totalClams = UPGRADE_CONFIG.machines.basicClam.amount + UPGRADE_CONFIG.machines.advancedClam.amount + UPGRADE_CONFIG.machines.premiumClam.amount;
- // Check if we've reached max clams
- if (totalClams >= 4) {
- // Find all basic clam upgrade texts and update them
- tabContainers['clams'].children.forEach(function (child) {
- if (child.text && child.text.includes("BP")) {
- var nameText = tabContainers['clams'].children.find(function (c) {
- return c.text === UPGRADE_CONFIG.machines.basicClam.name;
- });
- if (nameText && child.y > nameText.y && child.y < nameText.y + 150) {
- child.setText("SOLD OUT");
- child.fill = 0x888888; // Gray color
- }
- }
- });
- refreshUpgradeTab('clams'); // Refresh entire clams tab
- }
- }
bpText.setText(formatBP(game.bp) + " BP");
- costText.setText(getUpgradeCost(upgrade) + " BP");
- // Update clam visuals if needed
+ updateCostText(category, key, getUpgradeCost(upgrade) + " BP", 0xFFFF00);
+ // Update visuals
if (category === 'machines') {
updateClamVisuals();
- }
- // Update decoration visuals if implemented
- if (category === 'decorations') {
+ } else if (category === 'decorations') {
if (key === 'bubbleCoral') {
updateCoralDecorations();
} else if (key === 'sunkenTreasures') {
updateTreasureDecorations();
}
- // Future decoration handlers would go here
}
}
} else if (upgrade.currentLevel < upgrade.maxLevel) {
// For regular upgrades with levels
upgrade.currentLevel++;
game.bp -= cost;
bpText.setText(formatBP(game.bp) + " BP");
- // If this is a color upgrade, update the UI to reflect dependency status
+ // If this is a color upgrade, update the UI
if (category === 'colors') {
refreshUpgradeTab('colors');
return true;
}
// Update cost text
if (upgrade.currentLevel >= upgrade.maxLevel) {
- costText.setText("SOLD OUT");
+ updateCostText(category, key, "SOLD OUT", 0x888888);
} else {
- costText.setText(getUpgradeCost(upgrade) + " BP");
+ updateCostText(category, key, getUpgradeCost(upgrade) + " BP", 0xFFFF00);
}
// Handle specific upgrade effects
if (category === 'player') {
if (key === 'lungCapacity') {
@@ -1901,9 +1293,8 @@
game.maxBubbleSize = baseSize * multiplier;
} else if (key === 'quickBreath') {
game.growthRate = UPGRADE_EFFECTS.quickBreath.baseValue * (1 + UPGRADE_EFFECTS.quickBreath.incrementPercent / 100 * upgrade.currentLevel);
}
- // Other upgrade effects will be implemented later
}
}
} else {
game.showError("Not enough BP!");
@@ -1914,34 +1305,279 @@
tabContainers[tab].addChild(hitContainer);
tabContainers[tab].addChild(nameText);
tabContainers[tab].addChild(costText);
}
-// Replace the existing code for creating upgrade texts with this:
-Object.keys(tabContainers).forEach(function (tab) {
- // Clear any existing content
- while (tabContainers[tab].children.length > 0) {
- tabContainers[tab].children[0].destroy();
+// Helper function to update cost text (NEW)
+function updateCostText(category, key, text, color) {
+ if (game.upgradeRegistry[category] && game.upgradeRegistry[category][key] && game.upgradeRegistry[category][key].costText) {
+ var costText = game.upgradeRegistry[category][key].costText;
+ costText.setText(text);
+ costText.fill = color;
}
- // Create left column for this tab
- if (tabColumns[tab] && tabColumns[tab].left) {
- tabColumns[tab].left.forEach(function (upgrade, index) {
- createUpgradeText(upgrade[0], upgrade[1], index, true, tab);
+}
+// Function to refresh upgrade tab (MODIFIED)
+function refreshUpgradeTab(tabName) {
+ // Clear the tab container
+ while (tabContainers[tabName].children.length > 0) {
+ tabContainers[tabName].children[0].destroy();
+ }
+ // Clear registry entries for this tab
+ Object.keys(game.upgradeRegistry).forEach(function (category) {
+ Object.keys(game.upgradeRegistry[category]).forEach(function (key) {
+ if (game.upgradeRegistry[category][key].tab === tabName) {
+ delete game.upgradeRegistry[category][key];
+ }
});
+ });
+ // Recreate all upgrades for the tab
+ if (tabColumns[tabName] && tabColumns[tabName].left) {
+ tabColumns[tabName].left.forEach(function (upgrade, index) {
+ createUpgradeText(upgrade[0], upgrade[1], index, true, tabName);
+ });
}
- // Create right column for this tab
- if (tabColumns[tab] && tabColumns[tab].right) {
- tabColumns[tab].right.forEach(function (upgrade, index) {
- createUpgradeText(upgrade[0], upgrade[1], index, false, tab);
+ if (tabColumns[tabName] && tabColumns[tabName].right) {
+ tabColumns[tabName].right.forEach(function (upgrade, index) {
+ createUpgradeText(upgrade[0], upgrade[1], index, false, tabName);
});
}
-});
-// Move the entire text container down by adjusting its Y position
-menuTextContainer.y = 0; // This should align it with the top of the panel instead of being above it
-menuTextContainer.x = 0; // Center in panel
-// Menu state and animation
-var menuOpen = false;
-var menuTargetY = game.height;
-// Update selection UI when colors change
+ // Update all cost texts for this tab
+ updateCostTexts(tabName);
+}
+// Function to update cost texts (NEW)
+function updateCostTexts(tabName) {
+ Object.keys(game.upgradeRegistry).forEach(function (category) {
+ Object.keys(game.upgradeRegistry[category]).forEach(function (key) {
+ var registry = game.upgradeRegistry[category][key];
+ // Only update elements in the current tab
+ if (registry.tab !== tabName) {
+ return;
+ }
+ var upgrade = UPGRADE_CONFIG[category][key];
+ var costText = registry.costText;
+ // Handle color upgrades
+ if (category === 'colors') {
+ var activeColorKey = getActiveColorKey();
+ if (upgrade.currentLevel > 0) {
+ if (key === activeColorKey || UPGRADE_CONFIG.gameSettings.activeColor === "auto" && key === activeColorKey) {
+ costText.setText("ACTIVE");
+ costText.fill = 0x00FF00;
+ } else if (upgrade.currentLevel >= upgrade.maxLevel) {
+ costText.setText("SOLD OUT");
+ costText.fill = 0x888888;
+ } else {
+ costText.setText(getUpgradeCost(upgrade) + " BP");
+ costText.fill = 0xFFFF00;
+ }
+ } else if (upgrade.requires) {
+ var required = UPGRADE_CONFIG.colors[upgrade.requires];
+ if (required && required.currentLevel === 0) {
+ costText.setText("LOCKED");
+ costText.fill = 0x888888;
+ } else {
+ costText.setText(getUpgradeCost(upgrade) + " BP");
+ costText.fill = 0xFFFF00;
+ }
+ }
+ }
+ // Handle machine upgrades
+ else if (category === 'machines') {
+ var totalClams = UPGRADE_CONFIG.machines.basicClam.amount + UPGRADE_CONFIG.machines.advancedClam.amount + UPGRADE_CONFIG.machines.premiumClam.amount;
+ if (totalClams >= 4 && key === 'basicClam') {
+ costText.setText("SOLD OUT");
+ costText.fill = 0x888888;
+ } else {
+ costText.setText(getUpgradeCost(upgrade) + " BP");
+ costText.fill = 0xFFFF00;
+ }
+ }
+ // Handle regular upgrades
+ else if (upgrade.currentLevel >= upgrade.maxLevel) {
+ costText.setText("SOLD OUT");
+ costText.fill = 0x888888;
+ } else {
+ costText.setText(getUpgradeCost(upgrade) + " BP");
+ costText.fill = 0xFFFF00;
+ }
+ });
+ });
+}
+// New function to update all upgrade texts
+function updateAllUpgradeTexts() {
+ menuTabs.forEach(function (tab) {
+ updateCostTexts(tab);
+ });
+}
+// Replace the old updateColorSelectionUI function with this
+function updateColorSelectionUI() {
+ updateCostTexts('colors');
+}
+// Variables for upgrade texts
+var upgradeTexts = [];
+var startY = 150;
+var upgradeSpacing = 250;
+var columnWidth = 1024;
+// Define legacy variables for backward compatibility
+var leftColumnUpgrades = [['player', 'lungCapacity'], ['player', 'quickBreath'], ['player', 'autoPop']];
+var rightColumnUpgrades = [['machines', 'basicClam'], ['machines', 'advancedClam'], ['machines', 'premiumClam'], ['machine', 'bubbleDurability'], ['machine', 'autoBubbleSpeed']];
+// Function to determine which tab an upgrade belongs to (for backward compatibility)
+function getTabForUpgrade(category, key) {
+ if (category === 'player') {
+ return 'bubbles';
+ }
+ if (category === 'machines' || category === 'machine') {
+ return 'clams';
+ }
+ if (category === 'colors') {
+ return 'colors';
+ }
+ if (category === 'decorations') {
+ return 'decorations';
+ }
+ return 'bubbles'; // Default
+}
+// Function to switch between tabs
+function switchTab(newTab) {
+ // Hide old tab content, show new tab content
+ tabContainers[currentTab].visible = false;
+ tabContainers[newTab].visible = true;
+ // Update tab button appearance
+ tabButtons[currentTab].alpha = 0.7;
+ tabButtons[newTab].alpha = 1.0;
+ currentTab = newTab;
+}
+// Function to update treasure decorations
+function updateTreasureDecorations() {
+ // Clear existing treasures
+ while (treasureContainer.children.length) {
+ treasureContainer.children[0].destroy();
+ }
+ // Clear zone tracking
+ game.treasureZones = [];
+ var treasureCount = UPGRADE_CONFIG.decorations.sunkenTreasures.amount;
+ if (treasureCount <= 0) {
+ return;
+ }
+ // Available treasure types
+ var treasureTypes = ['treasure1', 'treasure2', 'treasure3'];
+ // Position treasures at specific spots in the bottom half of screen
+ var positions = [
+ // Left side
+ {
+ x: game.width * 0.25,
+ y: game.height * 0.65
+ },
+ // Right side
+ {
+ x: game.width * 0.75,
+ y: game.height * 0.65
+ },
+ // Middle bottom
+ {
+ x: game.width * 0.5,
+ y: game.height * 0.8
+ }];
+ // Place treasures at predetermined spots
+ for (var i = 0; i < treasureCount; i++) {
+ // Don't exceed available positions
+ if (i >= positions.length) {
+ break;
+ }
+ // Choose treasure type based on position
+ var treasureType = treasureTypes[i % treasureTypes.length];
+ var pos = positions[i];
+ // Create circular zone indicator
+ var zoneRadius = game.width * 0.15;
+ var zoneIndicator = LK.getAsset('blower', {
+ width: zoneRadius * 2,
+ height: zoneRadius * 2,
+ shape: 'circle',
+ color: 0xFFFFFF,
+ alpha: 0.15,
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: pos.x,
+ y: pos.y
+ });
+ // Add zone to tracking for bonus calculation
+ game.treasureZones.push({
+ id: 'treasure_' + i,
+ x: pos.x,
+ y: pos.y,
+ radius: zoneRadius
+ });
+ // Create treasure sprite on top of zone
+ var treasure = LK.getAsset(treasureType, {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: pos.x,
+ y: pos.y,
+ scaleX: 1.8,
+ scaleY: 1.8,
+ alpha: 0.9
+ });
+ // Add zone first (so it's behind treasure)
+ treasureContainer.addChild(zoneIndicator);
+ treasureContainer.addChild(treasure);
+ }
+}
+// Function to update coral bubbles
+function updateCoralBubbles() {
+ if (UPGRADE_CONFIG.decorations.bubbleCoral.amount <= 0) {
+ return;
+ }
+ coralContainer.children.forEach(function (coral) {
+ // 5% chance per second to spawn bubble (0.083% per frame at 60fps)
+ if (Math.random() < 0.00083 || LK.ticks - coral.lastBubbleTime > 600) {
+ // Force spawn after 10 seconds
+ coral.lastBubbleTime = LK.ticks;
+ // Calculate bubble size based on player's max size
+ var bubbleSize = game.maxBubbleSize * (0.5 + Math.random() * 0.3);
+ // Spawn position slightly above coral
+ var bubbleX = coral.x + (Math.random() * 30 - 15);
+ var bubbleY = coral.y - coral.height * 0.3;
+ var bubble = spawnBubble(bubbleX, bubbleY, bubbleSize, 0, false);
+ if (bubble) {
+ // Set moderate upward velocity
+ bubble.verticalVelocity = -(2 + Math.random() * 3);
+ bubble.driftX = Math.random() * 2 - 1;
+ }
+ }
+ });
+}
+// Function to update coral decorations
+function updateCoralDecorations() {
+ // Clear existing corals
+ while (coralContainer.children.length) {
+ coralContainer.children[0].destroy();
+ }
+ // Position corals along bottom of screen
+ var coralCount = UPGRADE_CONFIG.decorations.bubbleCoral.amount;
+ if (coralCount <= 0) {
+ return;
+ }
+ // Available coral types
+ var coralTypes = ['coral1', 'coral2', 'coral3', 'coral4'];
+ // Space corals evenly along bottom
+ var spacing = game.width / (coralCount + 1);
+ for (var i = 0; i < coralCount; i++) {
+ // Choose random coral type
+ var coralType = coralTypes[Math.floor(Math.random() * coralTypes.length)];
+ // Create coral sprite
+ var coral = LK.getAsset(coralType, {
+ anchorX: 0.5,
+ anchorY: 1,
+ x: spacing * (i + 1),
+ y: game.height - 20,
+ // Slightly above bottom
+ scaleX: 1.5 + Math.random() * 0.5,
+ scaleY: 1.5 + Math.random() * 0.5
+ });
+ // Store last bubble spawn time
+ coral.lastBubbleTime = 0;
+ coralContainer.addChild(coral);
+ }
+}
+// Function to update clam visuals
function updateClamVisuals() {
while (clamContainer.children.length) {
clamContainer.children[0].destroy();
}
@@ -1993,80 +1629,54 @@
type: type,
isRight: isRight
});
clamContainer.addChild(sprite);
- // Add to the end of the updateClamVisuals() function:
- var totalClams = UPGRADE_CONFIG.machines.basicClam.amount + UPGRADE_CONFIG.machines.advancedClam.amount + UPGRADE_CONFIG.machines.premiumClam.amount;
- if (totalClams >= 4) {
- refreshUpgradeTab('clams');
- }
});
}
-updateClamVisuals();
-updateCoralDecorations();
-updateTreasureDecorations();
-// Add this to the end of the game initialization code, after updating the clam visuals
-function updateAllUpgradeTexts() {
- // Process left column upgrades
- leftColumnUpgrades.forEach(function (upgrade) {
- var category = upgrade[0];
- var key = upgrade[1];
- var upgradeConfig = UPGRADE_CONFIG[category][key];
- // Find the cost text for this upgrade
- Object.values(tabContainers).forEach(function (tabContainer) {
- tabContainer.children.forEach(function (child) {
- if (child.text && child.text.includes("BP") && child.y > tabContainer.children.find(function (c) {
- return c.text === upgradeConfig.name;
- }).y) {
- // Check if max level reached
- if (upgradeConfig.currentLevel >= upgradeConfig.maxLevel) {
- child.setText("SOLD OUT");
- }
- }
+// Function to update clams (spawn bubbles)
+function updateClams() {
+ if (!game.clamSpawnPoints) {
+ return;
+ }
+ game.clamSpawnPoints.forEach(function (spawnPoint) {
+ var config = UPGRADE_CONFIG.machines[spawnPoint.type];
+ // Calculate production time with speed upgrade
+ var baseTime = config.production * 150; // Convert to frames and further increase base time
+ var speedMultiplier = Math.pow(1 - UPGRADE_EFFECTS.autoBubbleSpeed.decrementPercent / 100, UPGRADE_CONFIG.machine.autoBubbleSpeed.currentLevel);
+ var adjustedTime = Math.max(1, Math.floor(baseTime * speedMultiplier));
+ var qualityLevel = UPGRADE_CONFIG.machine.bubbleQuality.currentLevel;
+ if (qualityLevel > 0) {
+ // -10% production rate per level
+ adjustedTime = Math.floor(adjustedTime * (1 + 0.1 * qualityLevel));
+ }
+ if (LK.ticks % adjustedTime === 0) {
+ // Find first available bubble in pool
+ var bubble = game.bubblePool.find(function (b) {
+ return !b.visible;
});
- });
- });
- // Process right column upgrades
- rightColumnUpgrades.forEach(function (upgrade) {
- var category = upgrade[0];
- var key = upgrade[1];
- if (category === 'machines') {
- var upgradeConfig = UPGRADE_CONFIG[category][key];
- var totalClams = UPGRADE_CONFIG.machines.basicClam.amount + UPGRADE_CONFIG.machines.advancedClam.amount + UPGRADE_CONFIG.machines.premiumClam.amount;
- // Find the cost text for this upgrade
- Object.values(tabContainers).forEach(function (tabContainer) {
- tabContainer.children.forEach(function (child) {
- if (child.text && child.text.includes("BP") && child.y > tabContainer.children.find(function (c) {
- return c.text === upgradeConfig.name;
- }).y) {
- // Check if sold out based on clam logic
- if (totalClams >= 4 && key === 'basicClam' || UPGRADE_CONFIG.machines.basicClam.amount <= UPGRADE_CONFIG.machines.advancedClam.amount && key === 'advancedClam' || UPGRADE_CONFIG.machines.advancedClam.amount <= UPGRADE_CONFIG.machines.premiumClam.amount && key === 'premiumClam') {
- child.setText("SOLD OUT");
- }
- }
- });
- });
- } else if (category === 'machine') {
- var upgradeConfig = UPGRADE_CONFIG[category][key];
- // Find the cost text for this upgrade
- Object.values(tabContainers).forEach(function (tabContainer) {
- tabContainer.children.forEach(function (child) {
- if (child.text && child.text.includes("BP") && child.y > tabContainer.children.find(function (c) {
- return c.text === upgradeConfig.name;
- }).y) {
- // Check if max level reached
- if (upgradeConfig.currentLevel >= upgradeConfig.maxLevel) {
- child.setText("SOLD OUT");
- }
- }
- });
- });
+ if (bubble && game.activeBubbles.length < game.MAX_BUBBLES) {
+ bubble.activate(spawnPoint.x, spawnPoint.y, config.bubbleSize, false);
+ bubble.fromClam = true;
+ if (UPGRADE_CONFIG.player.sizeVariance.currentLevel > 0) {
+ var variance = UPGRADE_CONFIG.player.sizeVariance.currentLevel;
+ var minIncrease = 0.1 * variance; // +10% per level to min size
+ var maxIncrease = 0.15 * variance; // +15% per level to max size
+ // Apply size variance
+ var sizeMultiplier = 1 - minIncrease + Math.random() * (minIncrease + maxIncrease);
+ bubble.size *= sizeMultiplier;
+ }
+ // Set initial velocities for clam bubbles
+ bubble.verticalVelocity = 0;
+ bubble.driftX = (spawnPoint.isRight ? -1 : 1) * (Math.random() * 1.5 + 2);
+ game.activeBubbles.push(bubble);
+ }
}
});
}
-// Call the function after creating all upgrades
-updateAllUpgradeTexts();
-// Initialize game variables
+// Initialize twin bubbles array
+game.twinBubbles = [];
+game.treasureZones = [];
+// Initialize game variables for bubbles
game.growingBubble = null;
game.lastMouthState = false; // Track previous mouth state
game.mouthOpenDuration = 0; // Track how long mouth has been open
game.MOUTH_OPEN_THRESHOLD = 10; // Frames required with mouth open to start bubble
@@ -2074,17 +1684,21 @@
game.blowCooldown = 0; // Cooldown timer between bubble starts
game.BLOW_COOLDOWN_TIME = 15; // Frames to wait between new bubbles
game.maxBubbleSize = 120; // Increased by 30%
game.growthRate = UPGRADE_EFFECTS.quickBreath.baseValue * (1 + UPGRADE_EFFECTS.quickBreath.incrementPercent / 100 * UPGRADE_CONFIG.player.quickBreath.currentLevel);
+// Create bubble pool
game.bubblePool = Array(250).fill(null).map(function () {
return new Bubble();
});
game.activeBubbles = [];
game.MAX_BUBBLES = 200; // Active bubble limit
+// Add bubbles to game
game.bubblePool.forEach(function (bubble) {
game.addChild(bubble);
});
+// Set base spawn rate
game.baseSpawnRate = 180; // Every 3 seconds
+// Function to spawn a bubble
function spawnBubble(x, y, size) {
var direction = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
var isAutoPop = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
if (game.activeBubbles.length >= game.MAX_BUBBLES) {
@@ -2107,107 +1721,9 @@
}
game.activeBubbles.push(bubble);
return bubble;
}
-// Initialize game variables
-//<Assets used in the game will automatically appear here>
-game.bp = 0; // Track total BP
-game.combo = 0;
-game.lastPopTime = 0;
-game.COMBO_WINDOW = 60; // 1 second in frames
-function formatBP(value) {
- var units = ['', 'K', 'M', 'B', 'T'];
- var unitIndex = 0;
- while (value >= 1000 && unitIndex < units.length - 1) {
- value /= 1000;
- unitIndex++;
- }
- return Math.floor(value * 10) / 10 + units[unitIndex];
-}
-// Create BP display text (add near game initialization)
-var bpText = new Text2("0 BP", {
- size: 120,
- fill: 0xFFFFFF,
- stroke: 0x33caf8,
- strokeThickness: 4,
- font: "Impact",
- fontWeight: "bold"
-});
-bpText.anchor.set(1, 0);
-bpText.x = game.width - 20;
-bpText.y = 20;
-game.addChild(bpText);
-game.addBP = function (points, x, y, isAutoPop) {
- var currentTime = LK.ticks;
- // Only update combo if it's not an auto-pop
- if (!isAutoPop) {
- if (currentTime - game.lastPopTime < game.COMBO_WINDOW) {
- game.combo++;
- points *= 1 + game.combo * 0.1; // 10% bonus per combo
- } else {
- game.combo = 0;
- }
- game.lastPopTime = currentTime;
- }
- // Ensure points is at least 1
- points = Math.max(1, Math.floor(points));
- game.bp += points;
- bpText.setText(formatBP(game.bp) + " BP");
- // Set size and color based on point value
- var textSize = 96;
- var textColor = 0xFFFF00; // Default yellow
- if (points > 100) {
- textSize = 120;
- textColor = 0xFF0000; // Red for >100
- } else if (points > 50) {
- textSize = 108;
- textColor = 0xFFA500; // Orange for 51-100
- }
- // Always show point text regardless of auto or manual pop
- var pointText = new Text2("+" + points, {
- size: textSize,
- fill: textColor,
- font: "Impact",
- fontWeight: 'bold'
- });
- pointText.anchorX = 0.5;
- pointText.anchorY = 0.5;
- pointText.x = x;
- pointText.y = y;
- game.addChild(pointText);
- tween(pointText, {
- y: pointText.y - 100,
- alpha: 0
- }, {
- duration: 1200,
- onFinish: function onFinish() {
- pointText.destroy();
- }
- });
- // Only show combo text if it's a manual pop and we have a combo
- if (!isAutoPop && game.combo > 0) {
- var comboText = new Text2("x" + (game.combo + 1), {
- size: 96,
- fill: 0xFFA500,
- stroke: 0x000000,
- strokeThickness: 4,
- fontWeight: 'bold'
- });
- comboText.anchorX = 0.5;
- comboText.anchorY = 0;
- comboText.x = game.width / 2;
- comboText.y = 20;
- game.addChild(comboText);
- tween(comboText, {
- alpha: 0
- }, {
- duration: 500,
- onFinish: function onFinish() {
- comboText.destroy();
- }
- });
- }
-};
+// Game update function
game.update = function () {
updateCoralBubbles();
// Update mouth state and duration
if (!game.lastMouthState) {
@@ -2265,12 +1781,8 @@
var breathLevel = UPGRADE_CONFIG.player.bubbleBreath.currentLevel;
if (breathLevel > 0) {
// Calculate chances for extra bubbles
var extraBubbles = 0;
- // Level 1: 20% for +1
- // Level 2: 40% for +1
- // Level 3: 60% for +1, 20% for +2
- // Level 4: 80% for +1, 40% for +2
var rand = Math.random();
if (rand < breathLevel * 0.2) {
extraBubbles++;
// Check for 2nd extra bubble at level 3-4
@@ -2300,16 +1812,17 @@
game.blowCooldown--;
}
game.lastMouthState = facekit.mouthOpen;
updateClams();
- // Inside game.update, after other updates
+ // Fish spawning (auto-pop upgrade)
if (UPGRADE_CONFIG.player.autoPop.currentLevel > 0) {
// 8 seconds (480 frames) base, reduced by 2 seconds (120 frames) per level
if (LK.ticks % Math.max(60, 660 - UPGRADE_CONFIG.player.autoPop.currentLevel * 120) === 0) {
var fish = new Fish();
game.addChild(fish);
}
}
+ // Random bubble spawning
if (game.activeBubbles.length < game.MAX_BUBBLES) {
if (LK.ticks % game.baseSpawnRate == 0) {
var x = Math.random() * (game.width - 200) + 100;
spawnBubble(x, game.height + 100, 100, 0, true);
@@ -2322,8 +1835,9 @@
return false;
}
return true;
});
+ // Update all active bubbles
game.activeBubbles.forEach(function (bubble) {
if (bubble.update) {
bubble.update();
}
@@ -2346,31 +1860,26 @@
if (menuOpen) {
game.setChildIndex(menuContainer, game.children.length - 1);
}
tween(menuContainer, {
- y: targetY //{9O.1}
+ y: targetY
}, {
- //{9O.2}
duration: 300,
- //{9O.3}
easing: tween.easeOutBack,
- //{9O.4}
onFinish: function onFinish() {
- tabsContainer.visible = menuOpen; // Show/hide tabs based on menu state //{9Q.1}
+ tabsContainer.visible = menuOpen; // Show/hide tabs based on menu state
if (!menuOpen) {
- //{9Q.2}
- game.setChildIndex(menuContainer, 1); //{9Q.3}
- } //{9Q.4}
- } //{9Q.5}
+ game.setChildIndex(menuContainer, 1);
+ }
+ }
});
return true;
}
if (menuOpen) {
return true; // Let containers handle their own clicks
}
- // Bubble popping logic remains the same
+ // Bubble popping logic
var popped = false;
- // NEW:
for (var i = game.activeBubbles.length - 1; i >= 0; i--) {
var bubble = game.activeBubbles[i];
var dx = x - bubble.x;
var dy = y - bubble.y;
@@ -2380,5 +1889,24 @@
popped = true;
break;
}
}
-};
\ No newline at end of file
+};
+// Initialize decoration visuals
+updateClamVisuals();
+updateCoralDecorations();
+updateTreasureDecorations();
+// Initialize upgrade texts for all tabs
+menuTabs.forEach(function (tab) {
+ if (tabColumns[tab] && tabColumns[tab].left) {
+ tabColumns[tab].left.forEach(function (upgrade, index) {
+ createUpgradeText(upgrade[0], upgrade[1], index, true, tab);
+ });
+ }
+ if (tabColumns[tab] && tabColumns[tab].right) {
+ tabColumns[tab].right.forEach(function (upgrade, index) {
+ createUpgradeText(upgrade[0], upgrade[1], index, false, tab);
+ });
+ }
+});
+// Update all upgrade texts to their correct initial state
+updateAllUpgradeTexts();
\ No newline at end of file
A treasure chest with gold coins. Cartoon.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
A golden skull with diamonds for eyes. Cartoon.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
A golden necklace with a ruby pendant. Cartoon.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
A filled in white circle.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
A yellow star. Cartoon.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
a game logo for a game called 'Bubble Blower Tycoon' about a happy purple pufferfish with yellow fins and spines that builds an underwater empire of bubbles. Cartoon. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
an SVG of the word 'Start'. word should be yellow and the font should look like its made out of bubbles. cartoon. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
bubblelow
Sound effect
backgroundmusic
Music
bubblehigh
Sound effect
bubble1
Sound effect
bubble2
Sound effect
bubble3
Sound effect
bubble4
Sound effect
blowing
Sound effect
bubbleshoot
Sound effect
fishtank
Sound effect
menuopen
Sound effect
upgrade
Sound effect
jellyfish
Sound effect
titlemusic
Music
startbutton
Sound effect