From 0365f4542d1889d062dfb0ce83c05f5955a815b9 Mon Sep 17 00:00:00 2001 From: Darkages Date: Sun, 14 Jun 2026 20:45:06 +0000 Subject: [PATCH] Initial Push --- docker-compose.yml | 9 + game.js | 732 +++++++++++++++++++++++++++++++++++++++++++++ index.html | 374 +++++++++++++++++++++++ style.css | 413 +++++++++++++++++++++++++ 4 files changed, 1528 insertions(+) create mode 100644 docker-compose.yml create mode 100644 game.js create mode 100644 index.html create mode 100644 style.css diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..0b4a3ef --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,9 @@ +version: "3" + +services: + client: + image: nginx + ports: + - 82:80 + volumes: + - ./:/usr/share/nginx/html diff --git a/game.js b/game.js new file mode 100644 index 0000000..93505f4 --- /dev/null +++ b/game.js @@ -0,0 +1,732 @@ +// ============================================ +// GAME STATE & INITIALIZATION +// ============================================ + +let state = { + humans: 0, + prayers: 0, + grace: 0, + sacredVessels: 0, + holyScripture: 0, + blessings: 0, + manna: 0, + souls: 0, + wisdom: 0, + miracles: 0, + auras: 0, + sacredIcons: 0, + + commonCount: 0, + principalityCount: 0, + powerCount: 0, + virtueCount: 0, + dominionCount: 0, + thronesCount: 0, + cherubCount: 0, + seraphCount: 0, + archangelCount: 0, + + commonBaseCost: 50, + principalityBaseCost: 150, + powerBaseCost: 250, + virtueBaseCost: 400, + dominionBaseCost: 600, + thronesBaseCost: 800, + cherubBaseCost: 1000, + seraphBaseCost: 1500, + archangelCost: 500, + + unlockRequirements: { + tier2: 50, + tier3: 100, + tier4: 150, + tier5: 200, + tier6: 250, + tier7: 300, + tier8: 350, + tier9: 0 + }, + + costScalingFactor: 1.15, + globalMultiplier: 1.0, + ascensionCount: 0, + lastTick: Date.now() +}; + +let soundEnabled = true; +let audioCtx = null; + +// ============================================ +// SOUND FUNCTIONS +// ============================================ + +function initAudio() { + if (!audioCtx) { + audioCtx = new (window.AudioContext || window.webkitAudioContext)(); + } +} + +function playClickSound() { + if (!soundEnabled || !audioCtx) return; + const osc = audioCtx.createOscillator(); + const gain = audioCtx.createGain(); + osc.connect(gain); + gain.connect(audioCtx.destination); + osc.frequency.value = 440; + gain.gain.setValueAtTime(0.3, audioCtx.currentTime); + gain.gain.exponentialRampToValueAtTime(0.01, audioCtx.currentTime + 0.1); + osc.start(); + osc.stop(audioCtx.currentTime + 0.1); +} + +function playBuySound() { + if (!soundEnabled || !audioCtx) return; + const osc = audioCtx.createOscillator(); + const gain = audioCtx.createGain(); + osc.connect(gain); + gain.connect(audioCtx.destination); + osc.frequency.value = 523.25; + gain.gain.setValueAtTime(0.3, audioCtx.currentTime); + gain.gain.exponentialRampToValueAtTime(0.01, audioCtx.currentTime + 0.2); + osc.start(); + osc.stop(audioCtx.currentTime + 0.2); +} + +function playPrestigeSound() { + if (!soundEnabled || !audioCtx) return; + const notes = [523.25, 659.25, 783.99, 1046.50]; + let time = audioCtx.currentTime; + notes.forEach((freq, i) => { + setTimeout(() => { + const osc = audioCtx.createOscillator(); + const gain = audioCtx.createGain(); + osc.connect(gain); + gain.connect(audioCtx.destination); + osc.frequency.value = freq; + gain.gain.setValueAtTime(0.3, time + i * 100 / 1000); + gain.gain.exponentialRampToValueAtTime(0.01, time + i * 100 / 1000 + 0.4); + osc.start(time + i * 100 / 1000); + osc.stop(time + i * 100 / 1000 + 0.4); + }, i * 100); + }); +} + +// ============================================ +// SIDE PANEL FUNCTIONS +// ============================================ + +function toggleSidePanel() { + const panel = document.getElementById('sidePanel'); + const overlay = document.getElementById('overlay'); + const btn = document.querySelector('.hamburger-btn'); + + if (panel.classList.contains('open')) { + closeSidePanel(); + } else { + panel.classList.add('open'); + overlay.classList.add('active'); + btn.classList.add('active'); + } +} + +function closeSidePanel() { + const panel = document.getElementById('sidePanel'); + const overlay = document.getElementById('overlay'); + const btn = document.querySelector('.hamburger-btn'); + + panel.classList.remove('open'); + overlay.classList.remove('active'); + btn.classList.remove('active'); +} + +// ============================================ +// VISUAL EFFECTS +// ============================================ + +function createFloatingNumber(x, y, amount, color = '#ffd700') { + const floatNum = document.createElement('div'); + floatNum.className = 'floating-number'; + + let textToDisplay = '+0'; + if (amount && !isNaN(amount)) { + textToDisplay = '+' + Math.round(Math.abs(amount)); + } + + floatNum.textContent = textToDisplay; + + const roundedAmount = amount ? Math.round(Math.abs(amount)) : 0; + floatNum.style.color = color; + floatNum.style.fontSize = (roundedAmount > 100 ? '2rem' : '1.5rem'); + floatNum.style.left = (x - 30) + 'px'; + floatNum.style.top = (y - 50) + 'px'; + + const offsetX = (Math.random() - 0.5) * 40; + floatNum.style.setProperty('--tx', offsetX + 'px'); + + document.body.appendChild(floatNum); + setTimeout(() => { floatNum.remove(); }, 1500); +} + +function createParticleBurst(x, y, color = '#ffd700') { + const particleCount = 12; + + for (let i = 0; i < particleCount; i++) { + const particle = document.createElement('div'); + particle.className = 'particle'; + + const size = Math.random() * 8 + 4; + particle.style.width = size + 'px'; + particle.style.height = size + 'px'; + + const colors = ['#ffd700', '#ffecb3', '#ffe082', '#fff59d', '#ffffff']; + particle.style.backgroundColor = colors[Math.floor(Math.random() * colors.length)]; + + particle.style.left = x + 'px'; + particle.style.top = y + 'px'; + + const angle = Math.random() * 2 * Math.PI; + const distance = Math.random() * 80 + 40; + const tx = Math.cos(angle) * distance + 'px'; + const ty = Math.sin(angle) * distance + 'px'; + + particle.style.setProperty('--tx', tx); + particle.style.setProperty('--ty', ty); + + document.body.appendChild(particle); + setTimeout(() => { particle.remove(); }, 1000); + } +} + +function createSparkle(x, y, color = '#ffd700') { + const sparkleCount = 8; + + for (let i = 0; i < sparkleCount; i++) { + setTimeout(() => { + const sparkle = document.createElement('div'); + sparkle.className = 'sparkle'; + sparkle.style.width = '20px'; + sparkle.style.height = '20px'; + sparkle.style.background = color; + sparkle.style.left = x + 'px'; + sparkle.style.top = y + 'px'; + + document.body.appendChild(sparkle); + setTimeout(() => { sparkle.remove(); }, 600); + }, i * 50); + } +} + +// ============================================ +// CALCULATION HELPERS +// ============================================ + +function calculatePrayerMultiplier() { + let multiplier = state.globalMultiplier; + + if (state.commonCount > 0) multiplier *= (1 + (state.commonCount * 0.01)); + if (state.principalityCount > 0) multiplier *= (1 + (state.principalityCount * 0.1)); + if (state.powerCount > 0) multiplier *= (1 + (state.powerCount * 0.15)); + if (state.virtueCount > 0) multiplier *= (1 + (state.virtueCount * 0.25)); + if (state.dominionCount > 0) multiplier *= (1 + (state.dominionCount * 0.2)); + if (state.thronesCount > 0) multiplier *= (1 + (state.thronesCount * 0.15)); + if (state.cherubCount > 0) multiplier *= (1 + (state.cherubCount * 0.25)); + if (state.seraphCount > 0) multiplier *= (1 + (state.seraphCount * 5)); + if (state.archangelCount > 0) multiplier *= (10 + (state.archangelCount * 2)); + + return multiplier; +} + +function calculateSoulsMultiplier() { + let multiplier = state.globalMultiplier; + + if (state.commonCount > 0) multiplier *= (1 + (state.commonCount * 0.5)); + if (state.principalityCount > 0) multiplier *= (1 + (state.principalityCount * 0.1)); + if (state.powerCount > 0) multiplier *= (1 + (state.powerCount * 0.15)); + + return multiplier; +} + +function getCostMultiplier() { + let costReduction = state.globalMultiplier; + if (state.cherubCount > 0) costReduction *= Math.pow(0.75, state.cherubCount); + return costReduction; +} + +function getCurrentCost(baseCost, count) { + const currentCost = baseCost * Math.pow(state.costScalingFactor, count); + const finalCost = currentCost * getCostMultiplier(); + return Math.round(finalCost); +} + +// ============================================ +// UI UPDATE FUNCTIONS +// ============================================ + +function showStatus(message) { + document.getElementById('status-display').textContent = message; +} + +function updateUI() { + const currencies = [ + { name: 'humans', displayId: 'sidebar-humans-display' }, + { name: 'prayers', displayId: 'sidebar-prayers-display' }, + { name: 'grace', displayId: 'sidebar-grace-display' }, + { name: 'sacredVessels', displayId: 'sidebar-vessel-display' }, + { name: 'holyScripture', displayId: 'sidebar-scripture-display' }, + { name: 'blessings', displayId: 'sidebar-blessing-display' }, + { name: 'manna', displayId: 'sidebar-manna-display' }, + { name: 'souls', displayId: 'sidebar-souls-display' }, + { name: 'wisdom', displayId: 'sidebar-wisdom-display' }, + { name: 'miracles', displayId: 'sidebar-miracle-display' }, + { name: 'auras', displayId: 'sidebar-aura-display' }, + { name: 'sacredIcons', displayId: 'sidebar-icon-display' } + ]; + + currencies.forEach(curr => { + const el = document.getElementById(curr.displayId); + if (el) el.textContent = Math.round(state[curr.name]); + }); + + const prayerMultiplier = calculatePrayerMultiplier(); + const totalPrayerGenPerSec = state.humans * 0.5; // Base Human Prayer Rate + + document.getElementById('prayer-click-rate').textContent = Math.round(totalPrayerGenPerSec * prayerMultiplier) + '/click'; + document.getElementById('holy-power').textContent = Math.round(totalPrayerGenPerSec * prayerMultiplier); + + const tierCounts = ['commonCount', 'principalityCount', 'powerCount', 'virtueCount', + 'dominionCount', 'thronesCount', 'cherubCount', 'seraphCount', 'archangelCount']; + + const countIds = ['common-count', 'principality-count', 'power-count', 'virtue-count', + 'dominion-count', 'throness-count', 'cherub-count', 'seraph-count', 'archangel-count']; + + tierCounts.forEach((countVar, i) => { + document.getElementById(countIds[i]).textContent = state[countVar]; + const panelCountId = 'panel-' + countIds[i]; + const panelEl = document.getElementById(panelCountId); + if (panelEl) panelEl.textContent = state[countVar]; + }); + + document.getElementById('global-multiplier').textContent = state.globalMultiplier.toFixed(1); + document.getElementById('ascension-count').textContent = state.ascensionCount; + + const costMult = getCostMultiplier(); + + const commonCost = getCurrentCost(state.commonBaseCost, state.commonCount); + const principalityCost = getCurrentCost(state.principalityBaseCost, state.principalityCount); + const powerCost = getCurrentCost(state.powerBaseCost, state.powerCount); + const virtueCost = getCurrentCost(state.virtueBaseCost, state.virtueCount); + const dominionCost = getCurrentCost(state.dominionBaseCost, state.dominionCount); + const thronesCost = getCurrentCost(state.thronesBaseCost, state.thronesCount); + const cherubCost = getCurrentCost(state.cherubBaseCost, state.cherubCount); + const seraphCost = getCurrentCost(state.seraphBaseCost, state.seraphCount); + + updatePanelAngelButtonsWithBatch(commonCost, principalityCost, powerCost, virtueCost, + dominionCost, thronesCost, cherubCost, seraphCost, costMult); + + const ascendCost = 1 * state.ascensionCount; + document.getElementById('ascend-btn').textContent = `Ascend to Heaven (Cost: ${ascendCost} Virtue Point${ascendCost > 1 ? 's' : ''})`; + + updateTierUnlocks(costMult); +} + +function getCurrencyNameForTier(tier) { + const mappings = { + 'common': 'Prayers', + 'principality': 'Grace', + 'power': 'Sacred Vessels', + 'virtue': 'Blessings', + 'dominion': 'Souls', + 'throne': 'Wisdom', + 'cherub': 'Manna', + 'seraph': 'Miracles', + 'archangel': 'Sacred Icons' + }; + return mappings[tier] || 'Resource'; +} + +function updatePanelAngelButtonsWithBatch(commonCost, principalityCost, powerCost, virtueCost, + dominionCost, thronesCost, cherubCost, seraphCost, costMult) { + + const updateQuickBuyButtons = (tierCardId, currencyKey, costPerUnit, baseAmounts = [1, 5, 10, 100]) => { + const card = document.getElementById(tierCardId); + if (!card) return; + + const currentCurrency = state[currencyKey]; + const quickBuyBtns = card.querySelectorAll('.quick-buys .buy-option-btn'); + + for (let i = 0; i < baseAmounts.length && quickBuyBtns[i]; i++) { + const amountToBuy = baseAmounts[i] * costPerUnit; + quickBuyBtns[i].disabled = currentCurrency < amountToBuy; + } + }; + + updateQuickBuyButtons('common-angel-panel-card', 'prayers', commonCost); + + // CORRECTED TIER 2: Checks Grace instead of Souls + if (state.grace >= state.unlockRequirements.tier2) { + const card = document.getElementById('principality-angel-panel-card'); + if (card) card.classList.remove('locked'); + + updateQuickBuyButtons('principality-angel-panel-card', 'grace', principalityCost); + } else { + const card = document.getElementById('principality-angel-panel-card'); + if (card) card.classList.add('locked'); + } + + if (state.sacredVessels >= state.unlockRequirements.tier3) { + const card = document.getElementById('power-angel-panel-card'); + if (card) card.classList.remove('locked'); + updateQuickBuyButtons('power-angel-panel-card', 'sacredVessels', powerCost); + } else { + const card = document.getElementById('power-angel-panel-card'); + if (card) card.classList.add('locked'); + } + + if (state.manna >= state.unlockRequirements.tier4) { + const card = document.getElementById('virtue-angel-panel-card'); + if (card) card.classList.remove('locked'); + updateQuickBuyButtons('virtue-angel-panel-card', 'blessings', virtueCost); + } else { + const card = document.getElementById('virtue-angel-panel-card'); + if (card) card.classList.add('locked'); + } + + if (state.wisdom >= state.unlockRequirements.tier5) { + const card = document.getElementById('dominion-angel-panel-card'); + if (card) card.classList.remove('locked'); + updateQuickBuyButtons('dominion-angel-panel-card', 'souls', dominionCost); + } else { + const card = document.getElementById('dominion-angel-panel-card'); + if (card) card.classList.add('locked'); + } + + if (state.miracles >= state.unlockRequirements.tier6) { + const card = document.getElementById('throne-angel-panel-card'); + if (card) card.classList.remove('locked'); + updateQuickBuyButtons('throne-angel-panel-card', 'wisdom', thronesCost); + } else { + const card = document.getElementById('throne-angel-panel-card'); + if (card) card.classList.add('locked'); + } + + if (state.auras >= state.unlockRequirements.tier7) { + const card = document.getElementById('cherub-angel-panel-card'); + if (card) card.classList.remove('locked'); + updateQuickBuyButtons('cherub-angel-panel-card', 'manna', cherubCost); + } else { + const card = document.getElementById('cherub-angel-panel-card'); + if (card) card.classList.add('locked'); + } + + if (state.sacredIcons >= state.unlockRequirements.tier8) { + const card = document.getElementById('seraph-angel-panel-card'); + if (card) card.classList.remove('locked'); + updateQuickBuyButtons('seraph-angel-panel-card', 'miracles', seraphCost); + } else { + const card = document.getElementById('seraph-angel-panel-card'); + if (card) card.classList.add('locked'); + } + + if (state.seraphCount > 0) { + const card = document.getElementById('archangel-angel-panel-card'); + if (card) card.classList.remove('locked'); + updateQuickBuyButtons('archangel-angel-panel-card', 'sacredIcons', state.archangelCost); + } else { + const card = document.getElementById('archangel-angel-panel-card'); + if (card) card.classList.add('locked'); + } +} + +function updateTierUnlocks(costMult) { + const tierCards = [ + { id: 'tier-1-card', unlocked: true }, + { id: 'tier-2-card', unlocked: state.souls >= state.unlockRequirements.tier2 }, + { id: 'tier-3-card', unlocked: state.sacredVessels >= state.unlockRequirements.tier3 }, + { id: 'tier-4-card', unlocked: state.manna >= state.unlockRequirements.tier4 }, + { id: 'tier-5-card', unlocked: state.wisdom >= state.unlockRequirements.tier5 }, + { id: 'tier-6-card', unlocked: state.miracles >= state.unlockRequirements.tier6 }, + { id: 'tier-7-card', unlocked: state.auras >= state.unlockRequirements.tier7 }, + { id: 'tier-8-card', unlocked: state.sacredIcons >= state.unlockRequirements.tier8 }, + { id: 'tier-9-card', unlocked: state.seraphCount > 0 } + ]; + + tierCards.forEach(tier => { + const card = document.getElementById(tier.id); + if (card) { + if (tier.unlocked) { + card.classList.remove('locked'); + card.classList.add('unlocked'); + } else { + card.classList.add('locked'); + card.classList.remove('unlocked'); + } + } + }); + + const tierIds = ['tier-2-card', 'tier-3-card', 'tier-4-card', 'tier-5-card', + 'tier-6-card', 'tier-7-card', 'tier-8-card']; + + const panelCardIds = ['principality-angel-panel-card', 'power-angel-panel-card', 'virtue-angel-panel-card', + 'dominion-angel-panel-card', 'throne-angel-panel-card', 'cherub-angel-panel-card', + 'seraph-angel-panel-card']; + + tierIds.forEach((tierId, i) => { + const card = document.getElementById(panelCardIds[i]); + if (card) { + if (tierCards[i+1].unlocked) { + card.classList.remove('locked'); + card.classList.add('unlocked'); + } else { + card.classList.add('locked'); + card.classList.remove('unlocked'); + } + } + }); + + const archCard = document.getElementById('archangel-angel-panel-card'); + if (archCard && tierCards[8].unlocked) { + archCard.classList.remove('locked'); + archCard.classList.add('unlocked'); + } else if (archCard) { + archCard.classList.add('locked'); + archCard.classList.remove('unlocked'); + } +} + +// ============================================ +// GAME LOGIC FUNCTIONS +// ============================================ + +function prayForAnswers(event) { + state.humans += 10; + updateUI(); + + const rect = event.target.getBoundingClientRect(); + const x = rect.left + rect.width / 2; + const y = rect.top + rect.height / 2; + + playClickSound(); + createFloatingNumber(x, y, 10, '#E91E63'); + createParticleBurst(x, y, '#E91E63'); + createSparkle(x, y, '#E91E63'); +} + +function buyAngel(tier, quantity) { + let baseCost, currentCurrency, currencyName, countVar; + + switch (tier) { + case 'common': baseCost = state.commonBaseCost; currentCurrency = 'prayers'; currencyName = 'Prayers'; countVar = 'commonCount'; break; + case 'principality': baseCost = state.principalityBaseCost; currentCurrency = 'grace'; currencyName = 'Grace'; countVar = 'principalityCount'; break; + case 'power': baseCost = state.powerBaseCost; currentCurrency = 'sacredVessels'; currencyName = 'Sacred Vessels'; countVar = 'powerCount'; break; + case 'virtue': baseCost = state.virtueBaseCost; currentCurrency = 'blessings'; currencyName = 'Blessings'; countVar = 'virtueCount'; break; + case 'dominion': baseCost = state.dominionBaseCost; currentCurrency = 'souls'; currencyName = 'Souls'; countVar = 'dominionCount'; break; + case 'throne': baseCost = state.thronesBaseCost; currentCurrency = 'wisdom'; currencyName = 'Wisdom'; countVar = 'thronesCount'; break; + case 'cherub': baseCost = state.cherubBaseCost; currentCurrency = 'manna'; currencyName = 'Manna'; countVar = 'cherubCount'; break; + case 'seraph': baseCost = state.seraphBaseCost; currentCurrency = 'miracles'; currencyName = 'Miracles'; countVar = 'seraphCount'; break; + case 'archangel': baseCost = state.archangelCost; currentCurrency = 'sacredIcons'; currencyName = 'Sacred Icons'; countVar = 'archangelCount'; break; + default: return; + } + + const scaledBaseCost = getCurrentCost(baseCost, state[countVar]); + const costToPay = scaledBaseCost * quantity; + + if (state[currentCurrency] >= costToPay) { + const eventTarget = document.activeElement; + playBuySound(); + createFloatingNumber(eventTarget.getBoundingClientRect().left + 50, eventTarget.getBoundingClientRect().top, costToPay, '#4CAF50'); + createParticleBurst(eventTarget.getBoundingClientRect().left + 100, eventTarget.getBoundingClientRect().top, '#4CAF50'); + + state[currentCurrency] -= costToPay; + state[countVar] += quantity; + + showStatus(`Purchased ${quantity} x ${tier.toUpperCase()}!`); + updateUI(); + } else { + const eventTarget = document.activeElement; + showStatus(`Not enough ${currencyName}! Need ${costToPay}`); + createParticleBurst(eventTarget.getBoundingClientRect().left, eventTarget.getBoundingClientRect().top, '#FF5722'); + setTimeout(updateUI, 100); + } +} + +function prestigeAscend(event) { + const ascendCost = 1 * state.ascensionCount; + + if (state.virtuePoints >= ascendCost) { + state.virtuePoints -= ascendCost; + state.virtuePoints += 1; + state.ascensionCount++; + state.globalMultiplier *= 1.5; + + state.humans = 0; state.prayers = 0; state.souls = 0; + state.commonCount = 0; state.principalityCount = 0; state.powerCount = 0; + state.virtueCount = 0; state.dominionCount = 0; state.thronesCount = 0; + state.cherubCount = 0; state.seraphCount = 0; + + const rect = event.target.getBoundingClientRect(); + playPrestigeSound(); + createParticleBurst(rect.left + rect.width / 2, rect.top + rect.height / 2, '#ffd700'); + createSparkle(rect.left + rect.width / 2, rect.top + rect.height / 2, '#ffd700'); + + showStatus(`🌟 ASCENDED! Tiers Ascended: ${state.ascensionCount} | Multiplier: ${state.globalMultiplier.toFixed(1)}x`); + updateUI(); + } else { + const rect = event.target.getBoundingClientRect(); + showStatus(`Not enough Virtue Points! Need ${ascendCost}`); + event.target.style.background = '#c62828'; + setTimeout(() => event.target.style.background = '', 300); + } +} + +function saveGame() { + localStorage.setItem('celestialHierarchySave', JSON.stringify(state)); + showStatus('Game saved successfully!'); + if (soundEnabled) playClickSound(); + const rect = document.getElementById('save-btn').getBoundingClientRect(); + createFloatingNumber(rect.left + 50, rect.top - 20, '💾', '#2E7D32'); +} + +function loadGame() { + const saved = localStorage.getItem('celestialHierarchySave'); + + if (saved) { + try { + const loadedState = JSON.parse(saved); + state = {...state, ...loadedState}; + showStatus('Game loaded successfully!'); + } catch (e) { + showStatus('Load failed: corrupted save data'); + console.error(e); + } + } else { + showStatus('No save found. Starting new game!'); + } + + updateUI(); + + if (soundEnabled) playClickSound(); + const rect = document.getElementById('load-btn').getBoundingClientRect(); + createFloatingNumber(rect.left + 30, rect.top - 20, '📂', '#1976d2'); +} + +function newGame() { + if (confirm('Are you sure? All progress will be lost.')) { + localStorage.removeItem('celestialHierarchySave'); + + state = { + humans: 0, prayers: 0, grace: 0, sacredVessels: 0, holyScripture: 0, blessings: 0, manna: 0, souls: 0, wisdom: 0, miracles: 0, auras: 0, sacredIcons: 0, + commonCount: 0, principalityCount: 0, powerCount: 0, virtueCount: 0, dominionCount: 0, thronesCount: 0, cherubCount: 0, seraphCount: 0, archangelCount: 0, + commonBaseCost: 50, principalityBaseCost: 150, powerBaseCost: 250, virtueBaseCost: 400, dominionBaseCost: 600, thronesBaseCost: 800, cherubBaseCost: 1000, seraphBaseCost: 1500, archangelCost: 500, + unlockRequirements: { tier2: 50, tier3: 100, tier4: 150, tier5: 200, tier6: 250, tier7: 300, tier8: 350, tier9: 0 }, + costScalingFactor: 1.15, globalMultiplier: 1.0, ascensionCount: 0, lastTick: Date.now() + }; + + showStatus('Starting new game!'); + + if (soundEnabled) playClickSound(); + const rect = document.getElementById('new-btn').getBoundingClientRect(); + createFloatingNumber(rect.left + 30, rect.top - 20, '🆕', '#c62828'); + updateUI(); + } +} + +function toggleSound() { + soundEnabled = !soundEnabled; + document.getElementById('sound-status').textContent = soundEnabled ? 'ON' : 'OFF'; + + if (soundEnabled) playClickSound(); +} + +// ============================================ +// GAME LOOP +// ============================================ + +function gameLoop() { + const now = Date.now(); + const elapsed = Math.max((now - state.lastTick) / 1000, 0.01); + + let virtueGain = 0; + if (state.virtueCount > 0) virtueGain += state.virtueCount * 0.1 * elapsed; + if (state.dominionCount > 0) virtueGain += state.dominionCount * 0.2 * elapsed; + if (state.archangelCount > 0) virtueGain += state.archangelCount * 1.0 * elapsed; + state.virtuePoints += virtueGain; + + if (state.humans > 0) { + const prayerMultiplier = calculatePrayerMultiplier(); + const prayerRateFromHumans = state.humans * 0.5; + state.prayers += (prayerRateFromHumans * elapsed * prayerMultiplier); + } + + if (state.commonCount > 0) { + state.grace += (state.commonCount * 1 * elapsed); + } + + if (state.principalityCount > 0) { + state.sacredVessels += (state.souls * 0.1 * elapsed); + } + + if (state.powerCount > 0) { + state.holyScripture += (state.grace * 0.2 * elapsed); + } + + if (state.virtueCount > 0) { + state.manna += (state.sacredVessels * 0.15 * elapsed); + if (state.commonCount > 0) { + const soulsMultiplier = calculateSoulsMultiplier(); + state.souls += (state.prayers * 0.5 * elapsed * soulsMultiplier); + } + } + + if (state.dominionCount > 0) { + state.wisdom += (state.manna * 0.2 * elapsed); + } + + if (state.thronesCount > 0) { + state.miracles += (state.souls * 0.4 * elapsed); + } + + if (state.cherubCount > 0) { + state.auras += (state.wisdom * 0.15 * elapsed); + } + + if (state.seraphCount > 0) { + state.sacredIcons += (state.miracles * 0.25 * elapsed); + } + + state.lastTick = now; + updateUI(); +} + +// ============================================ +// INITIALIZATION +// ============================================ + +document.addEventListener('DOMContentLoaded', function() { + initAudio(); + + document.getElementById('prayer-btn').addEventListener('click', prayForAnswers); + + const quickBuyButtons = document.querySelectorAll('.buy-option-btn'); + quickBuyButtons.forEach(btn => { + const tier = btn.getAttribute('data-tier'); + const qty = parseInt(btn.getAttribute('data-qty')); + + if (tier && qty) { + btn.addEventListener('click', (e) => { + e.preventDefault(); + buyAngel(tier, qty); + }); + } + }); + + document.getElementById('ascend-btn').addEventListener('click', prestigeAscend); + + document.getElementById('save-btn').addEventListener('click', saveGame); + document.getElementById('load-btn').addEventListener('click', loadGame); + document.getElementById('new-btn').addEventListener('click', newGame); + document.getElementById('sound-toggle-btn').addEventListener('click', toggleSound); + + loadGame(); + updateUI(); + setInterval(gameLoop, 100); +}); \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..50282f5 --- /dev/null +++ b/index.html @@ -0,0 +1,374 @@ + + + + + + Celestial Hierarchy - Human Engine + + + + + + + + +
+ + +
+
+

👼 Angelic Summoning

+ +
+ +
View currencies in the Left Sidebar
+ + +
+ +
+
Tier 1
+
Common Angel
+
0
+
Cost: 50 Prayers
+
+1 Grace/sec each
+
+ + + + +
+
+ + +
+
Tier 2
+
Principalities Angel
+
0
+
Cost: 150 Grace
+ +
Requires 150 Grace to unlock Tier 2
+
+10% nearby bonus
+
+ + + + +
+
+ + +
+
Tier 3
+
Power Angel
+
0
+
Cost: 250 Sacred Vessels
+
Requires 100 Sacred Vessels to unlock Tier 3
+
+15% resource collection
+
+ + + + +
+
+ + +
+
Tier 4
+
Virtue Angel
+
0
+
Cost: 400 Blessings
+
Requires 150 Manna to unlock Tier 4
+
+25% miracle chance
+
+ + + + +
+
+ + +
+
Tier 5
+
Dominion Angel
+
0
+
Cost: 600 Souls
+
Requires 200 Wisdom to unlock Tier 5
+
+20% all output
+
+ + + + +
+
+ + +
+
Tier 6
+
Throne Angel
+
0
+
Cost: 800 Wisdom
+
Requires 250 Miracles to unlock Tier 6
+
+15% efficiency
+
+ + + + +
+
+ + +
+
Tier 7
+
Cherubim Guardian
+
0
+
Cost: 1000 Manna
+
Requires 300 Auras to unlock Tier 7
+
-25% spawn costs
+
+ + + + +
+
+ + +
+
Tier 8
+
Seraphim Fire Angel
+
0
+
Cost: 1500 Miracles
+
Requires 350 Sacred Icons to unlock Tier 8
+
+5x Prayer generation
+
+ + + + +
+
+ + +
+
Tier 9
+
Arch-Angel (Michael/Gabriel)
+
0
+
Cost: 500 Sacred Icons
+
Requires Tier 8 to unlock Tier 9
+
10x+ Multiplier! Ultimate!
+
+ + + + +
+
+
+
+ + +
+ + + + + +
+

🕊️ CELESTIAL HIERARCHY 🕊️

+

Ascend through the 9 Tiers of Heaven with 11 Currencies

+ + +
+

🌟 Angelic Tiers Unlocked

+ +
+
+
Tier 1
+
Common Angels
+
0
+
+1 Grace/sec | Cost: Prayers
+
+ +
+
Tier 2
+
Principalities
+
0
+
+10% bonus | Cost: Grace (150 Grace unlock)
+
+ +
+
Tier 3
+
Powers
+
0
+
+15% resource | Cost: Vessels (100 Vessels unlock)
+
+ +
+
Tier 4
+
Virtues
+
0
+
+25% miracle | Cost: Blessings (150 Manna unlock)
+
+ +
+
Tier 5
+
Dominions
+
0
+
+20% output | Cost: Souls (200 Wisdom unlock)
+
+ +
+
Tier 6
+
Thrones
+
0
+
+15% efficiency | Cost: Wisdom (250 Miracles unlock)
+
+ +
+
Tier 7
+
Cherubim
+
0
+
Cost Reduction | Cost: Manna (300 Auras unlock)
+
+ +
+
Tier 8
+
Seraphim
+
0
+
+5x Prayer | Cost: Miracles (350 Icons unlock)
+
+ +
+
Tier 9
+
Arch-Angels
+
0
+
10x+ Multiplier | Cost: Sacred Icons (Tier 8 unlock)
+
+
+
+ + +
+

🙏 Human Summoning

+ +
+ + +
+

🔯 Ascension (Prestige)

+

Reset progress for permanent bonuses!

+ + + +
+ ✨ Global Bonus: 1.0x +
+ +
+ Ascensions: 0 +
+
+ + +
+ + + +
+ + +
Welcome to Celestial Hierarchy!
+
+
+ + + + \ No newline at end of file diff --git a/style.css b/style.css new file mode 100644 index 0000000..7cdea93 --- /dev/null +++ b/style.css @@ -0,0 +1,413 @@ +* { margin: 0; padding: 0; box-sizing: border-box; } + +body { + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; + background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%); + color: #fff; + min-height: 100vh; + padding: 15px; + overflow-x: hidden; +} + +/* Main Layout Grid */ +.main-layout { + display: flex; + gap: 20px; + max-width: 1400px; + margin: 0 auto; +} + +.sidebar { + width: 300px; + flex-shrink: 0; +} + +.game-content { + flex-grow: 1; + min-width: 0; +} + +/* Hamburger Button */ +.hamburger-btn { + position: fixed; + top: 15px; + right: 280px; + background: linear-gradient(145deg, #7b1fa2, #4a148c); + border: none; + width: 50px; + height: 50px; + border-radius: 50%; + cursor: pointer; + z-index: 1001; + transition: all 0.3s ease; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3); +} + +.hamburger-btn:hover { transform: scale(1.1); background: linear-gradient(145deg, #9c27b0, #6a1b9a); } + +.hamburger-btn span { + display: block; + width: 24px; + height: 3px; + background: #fff; + margin: 5px auto; + border-radius: 3px; + transition: all 0.3s ease; +} + +.hamburger-btn.active span:nth-child(1) { transform: rotate(45deg) translate(8px, 8px); } +.hamburger-btn.active span:nth-child(2) { opacity: 0; } +.hamburger-btn.active span:nth-child(3) { transform: rotate(-45deg) translate(7px, -6px); } + +/* Side Panel */ +.side-panel { + position: fixed; + top: 0; + right: -400px; + width: 380px; + height: 100vh; + background: linear-gradient(145deg, #2a2a4a, #1e1e3a); + box-shadow: -5px 0 15px rgba(0, 0, 0, 0.5); + z-index: 1000; + transition: right 0.4s ease-in-out; + overflow-y: auto; + padding: 20px; +} + +.side-panel.open { right: 0; } + +.panel-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 20px; + padding-bottom: 15px; + border-bottom: 2px solid #ffd700; +} + +.panel-header h2 { color: #ffd700; font-size: 1.4rem; } + +.close-panel-btn { + background: transparent; + border: none; + color: #fff; + font-size: 24px; + cursor: pointer; + transition: all 0.3s ease; +} + +.close-panel-btn:hover { color: #ffd700; transform: rotate(90deg); } + +/* Currency Sidebar */ +.currency-frame { + background: linear-gradient(145deg, #2a2a4a, #1e1e3a); + border-radius: 10px; + padding: 15px; + margin-bottom: 20px; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3); +} + +.currency-frame h3 { + margin-bottom: 10px; + color: #ffd700; + font-size: 1.1rem; + text-align: center; +} + +.currency-row { + display: flex; + justify-content: space-between; + align-items: center; + padding: 8px 12px; + margin: 3px 0; + border-radius: 5px; + font-size: 0.9rem; +} + +.currency-name { + color: #fff; + font-weight: 600; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + max-width: 140px; +} + +.currency-amount { font-weight: bold; font-size: 1.1rem; min-width: 60px; text-align: right; } + +/* Currency Colors */ +.humans-currency { background-color: #FCE4EC; color: #E91E63; } +.prayers-currency { background-color: #E8F5E9; color: #2E7D32; } +.grace-currency { background-color: #FFF3E0; color: #E65100; } +.vessel-currency { background-color: #E3F2FD; color: #1565C0; } +.scripture-currency { background-color: #F3E5F5; color: #7B1FA2; } +.blessing-currency { background-color: #FFECB3; color: #FF8F00; } +.manna-currency { background-color: #C8E6C9; color: #388E3C; } +.souls-currency { background-color: #FFCCBC; color: #D84315; } +.wisdom-currency { background-color: #BBDEFB; color: #0277BD; } +.miracle-currency { background-color: #FFE0B2; color: #E65100; } +.aura-currency { background-color: #E1BEE7; color: #8E24AA; } +.icon-currency { background-color: #FFF9C4; color: #FBC02D; box-shadow: 0 0 5px #FFD700; } + +/* Tier Display */ +.tier-badge { + display: inline-block; + padding: 3px 6px; + border-radius: 3px; + font-size: 0.65rem; + font-weight: bold; + margin-right: 4px; +} + +.tier-common { background-color: #9E9E9E; color: white; } +.tier-principalities { background-color: #4CAF50; color: white; } +.tier-powers { background-color: #FF5722; color: white; } +.tier-virtues { background-color: #FFD700; color: black; } +.tier-dominions { background-color: #9C27B0; color: white; } +.tier-thrones { background-color: #03A9F4; color: white; } +.tier-cherubim { background-color: #8BC34A; color: black; } +.tier-seraphim { background-color: #E91E63; color: white; } +.tier-archangels { background-color: #FFD700; color: black; box-shadow: 0 0 15px #FFD700; } + +/* Tier Display Section */ +.tier-display-section { + background: linear-gradient(145deg, #2a2a4a, #1e1e3a); + border-radius: 10px; + padding: 15px; + margin-bottom: 20px; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3); +} + +.tier-display-section h3 { + color: #ffd700; + margin-bottom: 15px; + text-align: center; +} + +.tiers-grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 8px; + margin-top: 15px; +} + +.tier-card { + background: rgba(255, 255, 255, 0.05); + padding: 8px; + border-radius: 6px; + text-align: center; +} + +.tier-card.locked { opacity: 0.3; pointer-events: none; } +.tier-card.unlocked { opacity: 1; } + +.tier-name { font-size: 0.85rem; color: #ffd700; margin-bottom: 4px; } +.tier-count { font-size: 1rem; color: #fff; margin-bottom: 3px; } +.tier-desc { font-size: 0.65rem; color: #aaa; line-height: 1.2; } + +/* Prayer Section */ +.prayer-section { + background: linear-gradient(145deg, #2a2a4a, #1e1e3a); + border-radius: 10px; + padding: 15px; + margin-bottom: 20px; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3); +} + +.prayer-section h3 { margin-bottom: 15px; color: #ffd700; text-align: center; font-size: 1.2rem; } + +/* Click Button */ +.click-btn { + display: block; + width: 90%; + margin: 20px auto; + padding: 15px 30px; + font-size: 1.1rem; + background: linear-gradient(145deg, #7b1fa2, #4a148c); + color: white; + border: none; + border-radius: 10px; + cursor: pointer; + transition: all 0.3s ease; +} + +.click-btn:hover { background: linear-gradient(145deg, #9c27b0, #6a1b9a); transform: scale(1.02); } +.click-btn:active { transform: scale(0.98); } + +/* Panel Angel Cards */ +.angel-card { + background: rgba(255, 255, 255, 0.05); + padding: 15px; + border-radius: 8px; + margin-bottom: 15px; + transition: all 0.3s ease; +} + +.angel-card.locked { opacity: 0.4; pointer-events: none; } +.angel-card.unlocked { opacity: 1; } + +.premium-angel { border: 2px solid #ffd700; } + +.angel-name { font-size: 1rem; color: #ffd700; margin-bottom: 5px; } +.angel-count { font-size: 1.2rem; color: #fff; margin-bottom: 5px; } +.angel-cost { font-size: 0.85rem; color: #aaa; margin-bottom: 3px; } +.angel-buff { font-size: 0.7rem; color: #4CAF50; line-height: 1.2; margin-top: 3px; } + +/* Panel Angel Buttons */ +.buy-option-btn { + background: linear-gradient(145deg, #7b1fa2, #4a148c); + border: none; + padding: 6px 10px; + color: white; + font-size: 0.8rem; + cursor: pointer; + transition: all 0.3s ease; +} + +.buy-option-btn:hover:not(:disabled) { background: linear-gradient(145deg, #9c27b0, #6a1b9a); } +.buy-option-btn:disabled { opacity: 0.5; cursor: not-allowed; } + +.quick-buys { display: flex; gap: 5px; margin-top: 8px; justify-content: center; } + +/* Panel Unlock Requirements */ +.unlock-req { font-size: 0.7rem; color: #FFB300; margin-top: 4px; text-align: center; } + +/* Prestige Section */ +.prestige-section { + background: linear-gradient(145deg, #2a2a4a, #1e1e3a); + border-radius: 10px; + padding: 15px; + margin-bottom: 20px; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3); + border: 2px solid #ffd700; +} + +.prestige-section h3 { + color: #ffd700; + margin-bottom: 15px; + text-align: center; + font-size: 1.4rem; +} + +/* Prestige Counter */ +.prestige-counter { + text-align: center; + font-size: 2rem; + color: #ffd700; + margin-top: 15px; + text-shadow: 0 0 20px rgba(255, 215, 0, 0.8); +} + +.multiplier-display { + text-align: center; + font-size: 1.2rem; + color: #ffd700; + margin-top: 10px; +} + +/* Production Info */ +.production-info { + background: linear-gradient(145deg, #2a2a4a, #1e1e3a); + border-radius: 10px; + padding: 15px; + margin-bottom: 20px; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3); + font-size: 0.9rem; +} + +.production-info h4 { color: #ffd700; margin-bottom: 10px; } + +.production-item { + display: flex; + justify-content: space-between; + padding: 5px 0; + border-bottom: 1px solid rgba(255, 255, 255, 0.1); +} + +/* Action Buttons */ +.action-buttons { display: flex; justify-content: center; gap: 15px; margin: 15px 0; } + +.action-btn { + padding: 12px 25px; + border: none; + border-radius: 8px; + cursor: pointer; + font-size: 1rem; + transition: all 0.3s ease; +} + +.save-btn { background: linear-gradient(145deg, #2e7d32, #1b5e20); color: white; } +.load-btn { background: linear-gradient(145deg, #1976d2, #0d47a1); color: white; } +.new-btn { background: linear-gradient(145deg, #c62828, #b71c1c); color: white; } + +.action-btn:hover { transform: translateY(-2px); box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3); } + +/* Status */ +.status-bar { text-align: center; padding: 10px; font-size: 1rem; color: #aaa; min-height: 24px; margin-bottom: 15px;} + +/* Floating Numbers Animation */ +.floating-number { + position: fixed; + pointer-events: none; + z-index: 1000; + font-weight: bold; + animation: floatUp 1.5s ease-out forwards; +} + +@keyframes floatUp { + 0% { opacity: 1; transform: translateY(0) scale(1); } + 100% { opacity: 0; transform: translateY(-100px) scale(1.5); } +} + +/* Particle Effects */ +.particle { + position: fixed; + pointer-events: none; + z-index: 999; + border-radius: 50%; + animation: particleAnim 1s ease-out forwards; +} + +@keyframes particleAnim { + 0% { opacity: 1; transform: translate(0, 0) scale(1); } + 100% { opacity: 0; transform: translate(var(--tx), var(--ty)) scale(0.2); } +} + +/* Sparkle Effect */ +.sparkle { + position: fixed; + pointer-events: none; + z-index: 998; + animation: sparkleAnim 0.6s ease-out forwards; +} + +@keyframes sparkleAnim { + 0% { opacity: 1; transform: scale(0); } + 50% { opacity: 1; transform: scale(1.2); } + 100% { opacity: 0; transform: scale(0); } +} + +/* Sound Toggle */ +.sound-toggle { text-align: center; margin-top: 10px; } +.sound-btn { background: #333; color: #fff; padding: 8px 20px; border-radius: 5px; cursor: pointer; font-size: 0.9rem; border: none;} + +/* Backdrop overlay */ +.overlay { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.5); + z-index: 999; + display: none; +} + +.overlay.active { display: block; } + +/* Responsive adjustments */ +@media (max-width: 768px) { + .main-layout { flex-direction: column; } + .sidebar { width: 100%; } + .hamburger-btn { right: 15px; } +} \ No newline at end of file