732 lines
28 KiB
JavaScript
732 lines
28 KiB
JavaScript
// ============================================
|
|
// 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);
|
|
}); |