From 5bf53e3a4782d3781214994b5b2dc0997b3810b8 Mon Sep 17 00:00:00 2001 From: KoDer Date: Sat, 20 Jun 2026 00:47:13 +0700 Subject: [PATCH] =?UTF-8?q?=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=B8=D1=82?= =?UTF-8?q?=D1=8C=20kripto-magnat.html?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kripto-magnat.html | 324 +++++++++++++++++++++++++++++++++------------ 1 file changed, 243 insertions(+), 81 deletions(-) diff --git a/kripto-magnat.html b/kripto-magnat.html index 8e5ac12..daad20e 100644 --- a/kripto-magnat.html +++ b/kripto-magnat.html @@ -30,9 +30,10 @@ .tabs { display: flex; gap: 10px; margin-bottom: 20px; background: rgba(0,0,0,0.3); padding: 10px; border-radius: 12px; + flex-wrap: wrap; } .tab { - flex: 1; padding: 12px; border: none; border-radius: 8px; + flex: 1; min-width: 100px; padding: 12px; border: none; border-radius: 8px; background: rgba(255,255,255,0.05); color: #fff; cursor: pointer; font-size: 14px; font-weight: bold; transition: all 0.3s; } @@ -55,14 +56,23 @@ .crypto-item { background: rgba(255,255,255,0.05); padding: 15px; border-radius: 8px; margin-bottom: 10px; - display: grid; grid-template-columns: 2fr 1fr 1fr 1fr; gap: 10px; - align-items: center; border: 1px solid rgba(255,255,255,0.05); + border: 1px solid rgba(255,255,255,0.05); + } + .crypto-header { + display: flex; justify-content: space-between; align-items: center; + margin-bottom: 10px; } .crypto-name { font-weight: bold; font-size: 16px; } .crypto-price { color: #00f2fe; font-size: 18px; font-weight: bold; } - .crypto-change { font-size: 14px; } + .crypto-change { font-size: 14px; margin-left: 10px; } .crypto-change.up { color: #4caf50; } .crypto-change.down { color: #f44336; } + .crypto-buttons { + display: flex; gap: 5px; flex-wrap: wrap; + } + .crypto-buttons button { + flex: 1; min-width: 60px; padding: 8px 5px; + } .btn { padding: 8px 16px; border: none; border-radius: 6px; @@ -76,6 +86,14 @@ .btn:hover:not(:disabled) { transform: translateY(-2px); box-shadow: 0 5px 15px rgba(0,0,0,0.3); } .btn:disabled { opacity: 0.4; cursor: not-allowed; } + .quick-buy { + display: flex; gap: 5px; margin-top: 10px; + } + .quick-buy button { + flex: 1; padding: 6px; font-size: 11px; + background: rgba(76, 175, 80, 0.3); + } + .progress-bar { background: rgba(255,255,255,0.1); border-radius: 10px; height: 30px; overflow: hidden; margin: 10px 0; @@ -92,9 +110,10 @@ border-radius: 8px; margin-bottom: 10px; display: flex; justify-content: space-between; align-items: center; border: 1px solid rgba(255,255,255,0.05); + flex-wrap: wrap; gap: 10px; } .shop-item.owned { border-color: #4caf50; background: rgba(76, 175, 80, 0.1); } - .item-info { flex: 1; } + .item-info { flex: 1; min-width: 150px; } .item-name { font-weight: bold; font-size: 16px; margin-bottom: 5px; } .item-desc { font-size: 12px; opacity: 0.7; } .item-price { color: #ffd700; font-weight: bold; margin-right: 15px; } @@ -119,6 +138,7 @@ } .api-status.connected { color: #4caf50; } .api-status.error { color: #f44336; } + .api-status.fallback { color: #ff9800; } .transfer-section { background: rgba(255, 152, 0, 0.1); border: 1px solid rgba(255, 152, 0, 0.3); @@ -138,10 +158,20 @@ } .construction-stage.completed { border-color: #4caf50; background: rgba(76, 175, 80, 0.1); } .construction-stage.active { border-color: #00f2fe; background: rgba(0, 242, 254, 0.1); } + + .save-indicator { + position: fixed; bottom: 10px; right: 10px; + padding: 8px 16px; border-radius: 20px; + font-size: 12px; background: rgba(76, 175, 80, 0.9); + color: white; z-index: 1000; + opacity: 0; transition: opacity 0.3s; + } + .save-indicator.show { opacity: 1; }
⏳ API: ожидание...
+
💾 Сохранено!

💎 Крипто-Магнат

@@ -149,15 +179,15 @@
💵 Наличные
-
0
+
$10 000
₿ Крипто
-
0
+
$0
🏢 Бизнесы
-
0/сек
+
$0/сек
🏠 Дом
@@ -262,6 +292,7 @@ const INVESTOR_TABLE = 'investor_data'; const MY_SAVE = 'crypto_save'; const MY_TABLE = 'crypto_data'; + const LOCAL_STORAGE_KEY = 'cryptoTycoonSave'; let myState = { cash: 10000, @@ -305,6 +336,7 @@ let api = null; const statusEl = document.getElementById('apiStatus'); + const saveIndicator = document.getElementById('saveIndicator'); function updateStatus(text, type = '') { statusEl.textContent = text; @@ -320,6 +352,11 @@ while (el.children.length > 50) el.removeChild(el.lastChild); } + function showSaveIndicator() { + saveIndicator.classList.add('show'); + setTimeout(() => saveIndicator.classList.remove('show'), 2000); + } + // ═══════════════════════════════════════════════════════════ // API ИНИЦИАЛИЗАЦИЯ // ═══════════════════════════════════════════════════════════ @@ -351,49 +388,97 @@ setTimeout(() => { if (!api) { - updateStatus('✗ API недоступен', 'error'); - log('API недоступен', 'error'); + updateStatus('⚠️ API недоступен, используем localStorage', 'fallback'); + log('API недоступен, работаем с localStorage', 'warning'); + loadState(); + updateUI(); + renderCrypto(); + renderHouse(); + renderBusinesses(); + renderLuxury(); + + setInterval(tick, 1000); + setInterval(updateCryptoPrices, 3000); + setInterval(saveState, 10000); } }, 5000); // ═══════════════════════════════════════════════════════════ - // СОХРАНЕНИЕ / ЗАГРУЗКА + // СОХРАНЕНИЕ / ЗАГРУЗКА (С FALLBACK НА LOCALSTORAGE!) // ═══════════════════════════════════════════════════════════ async function loadState() { - if (!api) return; - try { - const result = await api.selectData(MY_TABLE, { key: 'state' }, MY_SAVE); - if (result.data && result.data.length > 0) { - myState = JSON.parse(result.data[0].value); - log('Состояние загружено', 'success'); + if (api) { + try { + const result = await api.selectData(MY_TABLE, { key: 'state' }, MY_SAVE); + if (result.data && result.data.length > 0) { + myState = JSON.parse(result.data[0].value); + log('Состояние загружено из API', 'success'); + return; + } + } catch (e) { + log('Ошибка загрузки API: ' + e.message, 'error'); + } + } + + // Fallback на localStorage + const saved = localStorage.getItem(LOCAL_STORAGE_KEY); + if (saved) { + try { + myState = JSON.parse(saved); + log('Состояние загружено из localStorage', 'success'); + } catch (e) { + log('Ошибка загрузки localStorage', 'error'); } - } catch (e) { - log('Ошибка загрузки: ' + e.message, 'error'); } } async function saveState() { - if (!api) return; + if (api) { + try { + await api.deleteData(MY_TABLE, { key: 'state' }, MY_SAVE); + await api.insertData(MY_TABLE, { + key: 'state', + value: JSON.stringify(myState), + updated_at: new Date().toISOString() + }, MY_SAVE); + showSaveIndicator(); + return; + } catch (e) { + log('Ошибка сохранения API: ' + e.message, 'error'); + } + } + + // Fallback на localStorage try { - await api.deleteData(MY_TABLE, { key: 'state' }, MY_SAVE); - await api.insertData(MY_TABLE, { - key: 'state', - value: JSON.stringify(myState), - updated_at: new Date().toISOString() - }, MY_SAVE); + localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(myState)); + showSaveIndicator(); } catch (e) { - log('Ошибка сохранения: ' + e.message, 'error'); + log('Ошибка сохранения localStorage: ' + e.message, 'error'); } } + // Автосохранение при закрытии страницы + window.addEventListener('beforeunload', () => { + if (api) { + navigator.sendBeacon('/api/save', JSON.stringify({ + table: MY_TABLE, + key: 'state', + value: JSON.stringify(myState), + save: MY_SAVE + })); + } + localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(myState)); + }); + // ═══════════════════════════════════════════════════════════ - // КРИПТО БИРЖА + // КРИПТО БИРЖА (ИСПРАВЛЕНО!) // ═══════════════════════════════════════════════════════════ function updateCryptoPrices() { for (let symbol in cryptos) { const change = (Math.random() - 0.5) * 0.1; cryptos[symbol].change = change; cryptos[symbol].price *= (1 + change); + if (cryptos[symbol].price < 0.000001) cryptos[symbol].price = 0.000001; } renderCrypto(); updateUI(); @@ -406,18 +491,33 @@ const crypto = cryptos[symbol]; const changeClass = crypto.change >= 0 ? 'up' : 'down'; const changeSign = crypto.change >= 0 ? '+' : ''; + const canBuy = myState.cash >= crypto.price; + const hasPortfolio = myState.portfolio[symbol] > 0; + list.innerHTML += `
-
-
${symbol}
-
${crypto.name}
+
+
+
${symbol}
+
${crypto.name}
+
+
+ $${crypto.price < 1 ? crypto.price.toFixed(6) : crypto.price.toFixed(2)} + ${changeSign}${(crypto.change * 100).toFixed(2)}% +
-
$${crypto.price.toFixed(2)}
-
${changeSign}${(crypto.change * 100).toFixed(2)}%
-
- - +
+ + + +
+ ${hasPortfolio ? ` +
+ У вас: ${myState.portfolio[symbol].toFixed(6)} ${symbol} + (≈$${(myState.portfolio[symbol] * crypto.price).toFixed(2)}) +
+ ` : ''}
`; } @@ -430,13 +530,22 @@ let html = ''; for (let symbol in myState.portfolio) { const amount = myState.portfolio[symbol]; + if (amount < 0.000001) continue; const value = amount * cryptos[symbol].price; totalValue += value; html += `
-
${symbol}
-
${amount.toFixed(6)}
-
$${value.toFixed(2)}
+
+
${symbol}
+
$${value.toFixed(2)}
+
+
+ ${amount.toFixed(6)} ${symbol} +
+
`; } @@ -447,33 +556,43 @@ document.getElementById('cryptoValue').textContent = '$' + Math.floor(totalValue).toLocaleString(); } - function buyCrypto(symbol) { - const amount = parseFloat(prompt(`Сколько ${symbol} купить? (цена: $${cryptos[symbol].price.toFixed(2)})`)); - if (!amount || amount <= 0) return; - const cost = amount * cryptos[symbol].price; - if (myState.cash < cost) { - log('Недостаточно средств', 'error'); + // Покупка на указанную сумму в долларах (ИСПРАВЛЕНО!) + function buyCryptoAmount(symbol, amountUsd) { + const price = cryptos[symbol].price; + if (myState.cash < amountUsd) { + log(`Недостаточно средств (есть $${Math.floor(myState.cash)}, нужно $${amountUsd})`, 'error'); return; } - myState.cash -= cost; + const amount = amountUsd / price; + myState.cash -= amountUsd; myState.portfolio[symbol] = (myState.portfolio[symbol] || 0) + amount; - log(`Куплено ${amount} ${symbol} за $${cost.toFixed(2)}`, 'success'); + log(`Куплено ${amount.toFixed(6)} ${symbol} за $${amountUsd}`, 'success'); + saveState(); renderCrypto(); updateUI(); } - function sellCrypto(symbol) { - const amount = parseFloat(prompt(`Сколько ${symbol} продать? (есть: ${myState.portfolio[symbol]})`)); - if (!amount || amount <= 0) return; - if (myState.portfolio[symbol] < amount) { - log('Недостаточно криптовалюты', 'error'); + // Покупка на процент от денег + function buyCryptoPercent(symbol, percent) { + const amountUsd = myState.cash * percent; + buyCryptoAmount(symbol, amountUsd); + } + + // Продажа процента от криптовалюты + function sellCryptoPercent(symbol, percent) { + if (!myState.portfolio[symbol] || myState.portfolio[symbol] < 0.000001) { + log(`У вас нет ${symbol}`, 'error'); return; } + const amount = myState.portfolio[symbol] * percent; const revenue = amount * cryptos[symbol].price; myState.cash += revenue; myState.portfolio[symbol] -= amount; - if (myState.portfolio[symbol] < 0.000001) delete myState.portfolio[symbol]; - log(`Продано ${amount} ${symbol} за $${revenue.toFixed(2)}`, 'success'); + if (myState.portfolio[symbol] < 0.000001) { + delete myState.portfolio[symbol]; + } + log(`Продано ${amount.toFixed(6)} ${symbol} за $${revenue.toFixed(2)}`, 'success'); + saveState(); renderCrypto(); updateUI(); } @@ -482,10 +601,10 @@ // ПЕРЕВОДЫ // ═══════════════════════════════════════════════════════════ async function transferFrom(source) { - if (!api) { log('API недоступен', 'error'); return; } + if (!api) { log('API недоступен для переводов', 'error'); return; } const input = document.getElementById(source === 'clicker' ? 'fromClicker' : 'fromInvestor'); const amount = parseFloat(input.value); - if (!amount || amount <= 0) { log('Введите сумму', 'error'); return; } + if (!amount || amount <= 0) { log('Введите корректную сумму', 'error'); return; } try { let sourceTable, sourceSave, sourceKey; @@ -509,7 +628,7 @@ const available = source === 'clicker' ? state.score : state.capital; if (available < amount) { - log('Недостаточно средств в источнике', 'error'); + log(`Недостаточно средств в источнике (есть ${Math.floor(available)}, нужно ${amount})`, 'error'); return; } @@ -527,8 +646,9 @@ }, sourceSave, source); myState.cash += amount; - log(`Получено $${amount} из ${source}`, 'success'); + log(`Получено $${amount.toLocaleString()} из ${source}`, 'success'); input.value = ''; + saveState(); updateUI(); await refreshAvailable(); } catch (e) { @@ -537,11 +657,14 @@ } async function transferTo(target) { - if (!api) { log('API недоступен', 'error'); return; } + if (!api) { log('API недоступен для переводов', 'error'); return; } const input = document.getElementById(target === 'clicker' ? 'toClicker' : 'toInvestor'); const amount = parseFloat(input.value); - if (!amount || amount <= 0) { log('Введите сумму', 'error'); return; } - if (myState.cash < amount) { log('Недостаточно средств', 'error'); return; } + if (!amount || amount <= 0) { log('Введите корректную сумму', 'error'); return; } + if (myState.cash < amount) { + log(`Недостаточно средств (есть $${Math.floor(myState.cash)}, нужно $${amount})`, 'error'); + return; + } try { let targetTable, targetSave, targetKey; @@ -576,8 +699,9 @@ }, targetSave, target); myState.cash -= amount; - log(`Отправлено $${amount} в ${target}`, 'success'); + log(`Отправлено $${amount.toLocaleString()} в ${target}`, 'success'); input.value = ''; + saveState(); updateUI(); } catch (e) { log('Ошибка перевода: ' + e.message, 'error'); @@ -616,12 +740,17 @@ container.innerHTML += `
-
+
${stage.name}
Стоимость: $${stage.cost.toLocaleString()} | Время: ${stage.time}с
- ${isActive ? `` : ''} + ${isActive && !isCompleted ? ` + + ` : ''} ${isCompleted ? '
✓ Готово
' : ''}
${isActive ? ` @@ -641,12 +770,19 @@ } const stage = houseStages[myState.house.stage]; if (myState.cash < stage.cost) { - log('Недостаточно средств', 'error'); + log(`Недостаточно средств (есть $${Math.floor(myState.cash)}, нужно $${stage.cost})`, 'error'); return; } - myState.cash -= stage.cost; - myState.house.progress = 0; - log(`Начато строительство: ${stage.name}`, 'success'); + if (myState.house.progress === 0) { + myState.cash -= stage.cost; + } + myState.house.progress += 10; + if (myState.house.progress >= 100) { + myState.house.stage++; + myState.house.progress = 0; + log(`Этап "${stage.name}" завершён!`, 'success'); + } + saveState(); renderHouse(); updateUI(); } @@ -663,7 +799,10 @@
${biz.name}
-
Доход: $${biz.income}/сек
+
+ Доход: $${biz.income}/сек + ${owned ? ` | Работников: ${myState.businesses[biz.id].workers} | Эффективность: x${myState.businesses[biz.id].efficiency.toFixed(1)}` : ''} +
$${biz.cost.toLocaleString()}