moved to angels
This commit is contained in:
+732
@@ -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);
|
||||
});
|
||||
Reference in New Issue
Block a user