@@ -59,6 +59,7 @@ let notifications = [] |
| 59 | 59 | // PHASE 3: Upgrade System |
| 60 | 60 | let playerPoints = 0 |
| 61 | 61 | let shopOpen = false |
| 62 | +let spentPoints = 0 |
| 62 | 63 | |
| 63 | 64 | // PHASE 4: Dawn Exhaustion System |
| 64 | 65 | let jumpStamina = 100 |
@@ -476,48 +477,99 @@ function setup () { |
| 476 | 477 | let numObstacles = Math.floor((width * height) / 60000) // More obstacles |
| 477 | 478 | numObstacles = constrain(numObstacles, 15, 25) |
| 478 | 479 | |
| 479 | | - // Create ant balloons |
| 480 | | - let numBalloons = Math.floor(random(15, 21)) |
| 481 | | - for (let i = 0; i < numBalloons; i++) { |
| 482 | | - let attempts = 0 |
| 483 | | - let placed = false |
| 484 | | - |
| 485 | | - while (!placed && attempts < 30) { |
| 486 | | - // Distribute balloons more evenly across the screen |
| 487 | | - let gridX = (i % 3) * (width / 3) + random(50, width / 3 - 50) |
| 488 | | - let gridY = Math.floor(i / 3) * (height / 4) + random(40, height / 4) |
| 489 | | - |
| 490 | | - let x = constrain(gridX, 80, width - 80) |
| 491 | | - let y = constrain(gridY, 60, height * 0.6) // Balloons in upper 60% of screen |
| 492 | | - let radius = random(35, 50) // Varied sizes for visual interest |
| 493 | | - |
| 494 | | - let valid = true |
| 495 | | - // Check distance from other obstacles |
| 496 | | - for (let obstacle of obstacles) { |
| 497 | | - if ( |
| 498 | | - dist(x, y, obstacle.x, obstacle.y) < |
| 499 | | - radius + obstacle.radius + 40 |
| 500 | | - ) { |
| 501 | | - valid = false |
| 502 | | - break |
| 480 | +// Create ant balloons |
| 481 | +let numBalloons = Math.floor(random(15, 21)) |
| 482 | +for (let i = 0; i < numBalloons; i++) { |
| 483 | + let attempts = 0 |
| 484 | + let placed = false |
| 485 | + |
| 486 | + while (!placed && attempts < 30) { |
| 487 | + // FIX: True random distribution with better spread |
| 488 | + let x, y |
| 489 | + |
| 490 | + // Use different strategies for better distribution |
| 491 | + let strategy = random() |
| 492 | + |
| 493 | + if (strategy < 0.3) { |
| 494 | + // 30% - Truly random across upper area |
| 495 | + x = random(80, width - 80) |
| 496 | + y = random(60, height * 0.5) |
| 497 | + } else if (strategy < 0.6) { |
| 498 | + // 30% - Radial distribution from center |
| 499 | + let angle = random(TWO_PI) |
| 500 | + let radius = random(100, min(width, height) * 0.35) |
| 501 | + x = width / 2 + cos(angle) * radius |
| 502 | + y = height * 0.35 + sin(angle) * radius * 0.7 // Elliptical, flatter |
| 503 | + x = constrain(x, 80, width - 80) |
| 504 | + y = constrain(y, 60, height * 0.6) |
| 505 | + } else if (strategy < 0.8) { |
| 506 | + // 20% - Edge preference for variety |
| 507 | + if (random() < 0.5) { |
| 508 | + x = random() < 0.5 ? random(80, 150) : random(width - 150, width - 80) |
| 509 | + y = random(60, height * 0.5) |
| 510 | + } else { |
| 511 | + x = random(80, width - 80) |
| 512 | + y = random(60, 120) |
| 513 | + } |
| 514 | + } else { |
| 515 | + // 20% - Poisson disk sampling attempt (avoid clusters) |
| 516 | + let bestX = random(80, width - 80) |
| 517 | + let bestY = random(60, height * 0.6) |
| 518 | + let bestMinDist = 0 |
| 519 | + |
| 520 | + // Try a few positions and pick the one furthest from existing balloons |
| 521 | + for (let j = 0; j < 5; j++) { |
| 522 | + let testX = random(80, width - 80) |
| 523 | + let testY = random(60, height * 0.6) |
| 524 | + let minDist = Infinity |
| 525 | + |
| 526 | + for (let obstacle of obstacles) { |
| 527 | + if (obstacle.type === 'balloon') { |
| 528 | + let d = dist(testX, testY, obstacle.x, obstacle.y) |
| 529 | + minDist = min(minDist, d) |
| 530 | + } |
| 531 | + } |
| 532 | + |
| 533 | + if (minDist > bestMinDist) { |
| 534 | + bestMinDist = minDist |
| 535 | + bestX = testX |
| 536 | + bestY = testY |
| 503 | 537 | } |
| 504 | 538 | } |
| 539 | + |
| 540 | + x = bestX |
| 541 | + y = bestY |
| 542 | + } |
| 505 | 543 | |
| 506 | | - // Check distance from home branch |
| 507 | | - if (valid && window.homeBranch) { |
| 508 | | - let branchY = window.homeBranch.y |
| 509 | | - if (Math.abs(y - branchY) < radius + 40) { |
| 510 | | - valid = false |
| 511 | | - } |
| 544 | + let radius = random(35, 50) // Varied sizes for visual interest |
| 545 | + |
| 546 | + let valid = true |
| 547 | + // Check distance from other obstacles |
| 548 | + for (let obstacle of obstacles) { |
| 549 | + if ( |
| 550 | + dist(x, y, obstacle.x, obstacle.y) < |
| 551 | + radius + obstacle.radius + 40 |
| 552 | + ) { |
| 553 | + valid = false |
| 554 | + break |
| 512 | 555 | } |
| 556 | + } |
| 513 | 557 | |
| 514 | | - if (valid) { |
| 515 | | - obstacles.push(new Obstacle(x, y, radius, 'balloon')) |
| 516 | | - placed = true |
| 558 | + // Check distance from home branch |
| 559 | + if (valid && window.homeBranch) { |
| 560 | + let branchY = window.homeBranch.y |
| 561 | + if (Math.abs(y - branchY) < radius + 40) { |
| 562 | + valid = false |
| 517 | 563 | } |
| 518 | | - attempts++ |
| 519 | 564 | } |
| 565 | + |
| 566 | + if (valid) { |
| 567 | + obstacles.push(new Obstacle(x, y, radius, 'balloon')) |
| 568 | + placed = true |
| 569 | + } |
| 570 | + attempts++ |
| 520 | 571 | } |
| 572 | +} |
| 521 | 573 | |
| 522 | 574 | // Create beetles |
| 523 | 575 | let numBeetles = Math.floor(random(9, 15)) |
@@ -1599,7 +1651,9 @@ function saveGame () { |
| 1599 | 1651 | upgrades: upgrades, |
| 1600 | 1652 | playerPoints: playerPoints, |
| 1601 | 1653 | nightsSurvived: nightsSurvived, |
| 1602 | | - currentNight: currentNight |
| 1654 | + currentNight: currentNight, |
| 1655 | + playerPoints: playerPoints, |
| 1656 | + spentPoints: spentPoints, |
| 1603 | 1657 | } |
| 1604 | 1658 | |
| 1605 | 1659 | localStorage.setItem('cobGameSave', JSON.stringify(saveData)) |
@@ -1617,6 +1671,8 @@ function loadGame () { |
| 1617 | 1671 | playerPoints = data.playerPoints || 0 |
| 1618 | 1672 | nightsSurvived = data.nightsSurvived || 0 |
| 1619 | 1673 | currentNight = data.currentNight || 1 |
| 1674 | + playerPoints = data.playerPoints || 0 |
| 1675 | + spentPoints = data.spentPoints || 0 |
| 1620 | 1676 | |
| 1621 | 1677 | // Apply upgrades |
| 1622 | 1678 | applyUpgradeEffects() |
@@ -1742,11 +1798,11 @@ function openUpgradeShop () { |
| 1742 | 1798 | noLoop() // Pause the game |
| 1743 | 1799 | |
| 1744 | 1800 | // Calculate points from flies caught this session |
| 1745 | | - playerPoints = totalFliesCaught |
| 1801 | + // playerPoints = totalFliesCaught |
| 1746 | 1802 | |
| 1747 | 1803 | // Update shop UI |
| 1748 | 1804 | document.getElementById('upgrade-shop').style.display = 'block' |
| 1749 | | - document.getElementById('available-points').textContent = playerPoints |
| 1805 | + document.getElementById('available-points').textContent = playerPoints - spentPoints |
| 1750 | 1806 | |
| 1751 | 1807 | // Populate upgrade lists |
| 1752 | 1808 | updateShopDisplay() |
@@ -1773,6 +1829,9 @@ function updateShopDisplay () { |
| 1773 | 1829 | let tier2HTML = '' |
| 1774 | 1830 | let tier1Count = 0 |
| 1775 | 1831 | |
| 1832 | + // Calculate available points |
| 1833 | + let availablePoints = playerPoints - spentPoints |
| 1834 | + |
| 1776 | 1835 | // Count tier 1 upgrades |
| 1777 | 1836 | for (let key in upgrades) { |
| 1778 | 1837 | if (upgrades[key].tier === 1 && upgrades[key].level > 0) { |
@@ -1784,7 +1843,7 @@ function updateShopDisplay () { |
| 1784 | 1843 | for (let key in upgrades) { |
| 1785 | 1844 | let upgrade = upgrades[key] |
| 1786 | 1845 | if (upgrade.tier === 1) { |
| 1787 | | - let canAfford = playerPoints >= upgrade.cost |
| 1846 | + let canAfford = availablePoints >= upgrade.cost |
| 1788 | 1847 | let maxed = upgrade.level >= upgrade.maxLevel |
| 1789 | 1848 | let buttonText = maxed ? 'MAXED' : `Buy (${upgrade.cost} pts)` |
| 1790 | 1849 | let buttonDisabled = maxed || !canAfford ? 'disabled' : '' |
@@ -1825,7 +1884,7 @@ function updateShopDisplay () { |
| 1825 | 1884 | let upgrade = upgrades[key] |
| 1826 | 1885 | if (upgrade.tier === 2) { |
| 1827 | 1886 | let unlocked = tier1Count >= upgrade.requires |
| 1828 | | - let canAfford = playerPoints >= upgrade.cost && unlocked |
| 1887 | + let canAfford = availablePoints >= upgrade.cost && unlocked |
| 1829 | 1888 | let maxed = upgrade.level >= upgrade.maxLevel |
| 1830 | 1889 | let buttonText = maxed |
| 1831 | 1890 | ? 'MAXED' |
@@ -1890,15 +1949,16 @@ window.buyUpgrade = function (upgradeKey) { |
| 1890 | 1949 | } |
| 1891 | 1950 | |
| 1892 | 1951 | // Check if can afford and not maxed |
| 1893 | | - if (playerPoints >= upgrade.cost && upgrade.level < upgrade.maxLevel) { |
| 1894 | | - playerPoints -= upgrade.cost |
| 1952 | + let availablePoints = playerPoints - spentPoints // Calculate available points |
| 1953 | + if (availablePoints >= upgrade.cost && upgrade.level < upgrade.maxLevel) { |
| 1954 | + spentPoints += upgrade.cost // Track spent points |
| 1895 | 1955 | upgrade.level++ |
| 1896 | 1956 | |
| 1897 | 1957 | // Apply upgrade effects immediately |
| 1898 | 1958 | applyUpgradeEffects() |
| 1899 | 1959 | |
| 1900 | | - // Update display |
| 1901 | | - document.getElementById('available-points').textContent = playerPoints |
| 1960 | + // Update display with available points |
| 1961 | + document.getElementById('available-points').textContent = playerPoints - spentPoints |
| 1902 | 1962 | updateShopDisplay() |
| 1903 | 1963 | |
| 1904 | 1964 | // Show notification |