Обновить kripto-magnat.html
This commit is contained in:
+225
-63
@@ -30,9 +30,10 @@
|
|||||||
.tabs {
|
.tabs {
|
||||||
display: flex; gap: 10px; margin-bottom: 20px;
|
display: flex; gap: 10px; margin-bottom: 20px;
|
||||||
background: rgba(0,0,0,0.3); padding: 10px; border-radius: 12px;
|
background: rgba(0,0,0,0.3); padding: 10px; border-radius: 12px;
|
||||||
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
.tab {
|
.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;
|
background: rgba(255,255,255,0.05); color: #fff; cursor: pointer;
|
||||||
font-size: 14px; font-weight: bold; transition: all 0.3s;
|
font-size: 14px; font-weight: bold; transition: all 0.3s;
|
||||||
}
|
}
|
||||||
@@ -55,14 +56,23 @@
|
|||||||
.crypto-item {
|
.crypto-item {
|
||||||
background: rgba(255,255,255,0.05); padding: 15px;
|
background: rgba(255,255,255,0.05); padding: 15px;
|
||||||
border-radius: 8px; margin-bottom: 10px;
|
border-radius: 8px; margin-bottom: 10px;
|
||||||
display: grid; grid-template-columns: 2fr 1fr 1fr 1fr; gap: 10px;
|
border: 1px solid rgba(255,255,255,0.05);
|
||||||
align-items: center; 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-name { font-weight: bold; font-size: 16px; }
|
||||||
.crypto-price { color: #00f2fe; font-size: 18px; font-weight: bold; }
|
.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.up { color: #4caf50; }
|
||||||
.crypto-change.down { color: #f44336; }
|
.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 {
|
.btn {
|
||||||
padding: 8px 16px; border: none; border-radius: 6px;
|
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: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; }
|
.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 {
|
.progress-bar {
|
||||||
background: rgba(255,255,255,0.1); border-radius: 10px;
|
background: rgba(255,255,255,0.1); border-radius: 10px;
|
||||||
height: 30px; overflow: hidden; margin: 10px 0;
|
height: 30px; overflow: hidden; margin: 10px 0;
|
||||||
@@ -92,9 +110,10 @@
|
|||||||
border-radius: 8px; margin-bottom: 10px;
|
border-radius: 8px; margin-bottom: 10px;
|
||||||
display: flex; justify-content: space-between; align-items: center;
|
display: flex; justify-content: space-between; align-items: center;
|
||||||
border: 1px solid rgba(255,255,255,0.05);
|
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); }
|
.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-name { font-weight: bold; font-size: 16px; margin-bottom: 5px; }
|
||||||
.item-desc { font-size: 12px; opacity: 0.7; }
|
.item-desc { font-size: 12px; opacity: 0.7; }
|
||||||
.item-price { color: #ffd700; font-weight: bold; margin-right: 15px; }
|
.item-price { color: #ffd700; font-weight: bold; margin-right: 15px; }
|
||||||
@@ -119,6 +138,7 @@
|
|||||||
}
|
}
|
||||||
.api-status.connected { color: #4caf50; }
|
.api-status.connected { color: #4caf50; }
|
||||||
.api-status.error { color: #f44336; }
|
.api-status.error { color: #f44336; }
|
||||||
|
.api-status.fallback { color: #ff9800; }
|
||||||
|
|
||||||
.transfer-section {
|
.transfer-section {
|
||||||
background: rgba(255, 152, 0, 0.1); border: 1px solid rgba(255, 152, 0, 0.3);
|
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.completed { border-color: #4caf50; background: rgba(76, 175, 80, 0.1); }
|
||||||
.construction-stage.active { border-color: #00f2fe; background: rgba(0, 242, 254, 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; }
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="api-status" id="apiStatus">⏳ API: ожидание...</div>
|
<div class="api-status" id="apiStatus">⏳ API: ожидание...</div>
|
||||||
|
<div class="save-indicator" id="saveIndicator">💾 Сохранено!</div>
|
||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h1>💎 Крипто-Магнат</h1>
|
<h1>💎 Крипто-Магнат</h1>
|
||||||
@@ -149,15 +179,15 @@
|
|||||||
<div class="status-bar">
|
<div class="status-bar">
|
||||||
<div class="status-item">
|
<div class="status-item">
|
||||||
<div class="status-label">💵 Наличные</div>
|
<div class="status-label">💵 Наличные</div>
|
||||||
<div class="status-value" id="cash">0</div>
|
<div class="status-value" id="cash">$10 000</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="status-item">
|
<div class="status-item">
|
||||||
<div class="status-label">₿ Крипто</div>
|
<div class="status-label">₿ Крипто</div>
|
||||||
<div class="status-value" id="cryptoValue">0</div>
|
<div class="status-value" id="cryptoValue">$0</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="status-item">
|
<div class="status-item">
|
||||||
<div class="status-label">🏢 Бизнесы</div>
|
<div class="status-label">🏢 Бизнесы</div>
|
||||||
<div class="status-value" id="businessIncome">0/сек</div>
|
<div class="status-value" id="businessIncome">$0/сек</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="status-item">
|
<div class="status-item">
|
||||||
<div class="status-label">🏠 Дом</div>
|
<div class="status-label">🏠 Дом</div>
|
||||||
@@ -262,6 +292,7 @@
|
|||||||
const INVESTOR_TABLE = 'investor_data';
|
const INVESTOR_TABLE = 'investor_data';
|
||||||
const MY_SAVE = 'crypto_save';
|
const MY_SAVE = 'crypto_save';
|
||||||
const MY_TABLE = 'crypto_data';
|
const MY_TABLE = 'crypto_data';
|
||||||
|
const LOCAL_STORAGE_KEY = 'cryptoTycoonSave';
|
||||||
|
|
||||||
let myState = {
|
let myState = {
|
||||||
cash: 10000,
|
cash: 10000,
|
||||||
@@ -305,6 +336,7 @@
|
|||||||
|
|
||||||
let api = null;
|
let api = null;
|
||||||
const statusEl = document.getElementById('apiStatus');
|
const statusEl = document.getElementById('apiStatus');
|
||||||
|
const saveIndicator = document.getElementById('saveIndicator');
|
||||||
|
|
||||||
function updateStatus(text, type = '') {
|
function updateStatus(text, type = '') {
|
||||||
statusEl.textContent = text;
|
statusEl.textContent = text;
|
||||||
@@ -320,6 +352,11 @@
|
|||||||
while (el.children.length > 50) el.removeChild(el.lastChild);
|
while (el.children.length > 50) el.removeChild(el.lastChild);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showSaveIndicator() {
|
||||||
|
saveIndicator.classList.add('show');
|
||||||
|
setTimeout(() => saveIndicator.classList.remove('show'), 2000);
|
||||||
|
}
|
||||||
|
|
||||||
// ═══════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════
|
||||||
// API ИНИЦИАЛИЗАЦИЯ
|
// API ИНИЦИАЛИЗАЦИЯ
|
||||||
// ═══════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════
|
||||||
@@ -351,29 +388,52 @@
|
|||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (!api) {
|
if (!api) {
|
||||||
updateStatus('✗ API недоступен', 'error');
|
updateStatus('⚠️ API недоступен, используем localStorage', 'fallback');
|
||||||
log('API недоступен', 'error');
|
log('API недоступен, работаем с localStorage', 'warning');
|
||||||
|
loadState();
|
||||||
|
updateUI();
|
||||||
|
renderCrypto();
|
||||||
|
renderHouse();
|
||||||
|
renderBusinesses();
|
||||||
|
renderLuxury();
|
||||||
|
|
||||||
|
setInterval(tick, 1000);
|
||||||
|
setInterval(updateCryptoPrices, 3000);
|
||||||
|
setInterval(saveState, 10000);
|
||||||
}
|
}
|
||||||
}, 5000);
|
}, 5000);
|
||||||
|
|
||||||
// ═══════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════
|
||||||
// СОХРАНЕНИЕ / ЗАГРУЗКА
|
// СОХРАНЕНИЕ / ЗАГРУЗКА (С FALLBACK НА LOCALSTORAGE!)
|
||||||
// ═══════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════
|
||||||
async function loadState() {
|
async function loadState() {
|
||||||
if (!api) return;
|
if (api) {
|
||||||
try {
|
try {
|
||||||
const result = await api.selectData(MY_TABLE, { key: 'state' }, MY_SAVE);
|
const result = await api.selectData(MY_TABLE, { key: 'state' }, MY_SAVE);
|
||||||
if (result.data && result.data.length > 0) {
|
if (result.data && result.data.length > 0) {
|
||||||
myState = JSON.parse(result.data[0].value);
|
myState = JSON.parse(result.data[0].value);
|
||||||
log('Состояние загружено', 'success');
|
log('Состояние загружено из API', 'success');
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log('Ошибка загрузки: ' + e.message, 'error');
|
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');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function saveState() {
|
async function saveState() {
|
||||||
if (!api) return;
|
if (api) {
|
||||||
try {
|
try {
|
||||||
await api.deleteData(MY_TABLE, { key: 'state' }, MY_SAVE);
|
await api.deleteData(MY_TABLE, { key: 'state' }, MY_SAVE);
|
||||||
await api.insertData(MY_TABLE, {
|
await api.insertData(MY_TABLE, {
|
||||||
@@ -381,19 +441,44 @@
|
|||||||
value: JSON.stringify(myState),
|
value: JSON.stringify(myState),
|
||||||
updated_at: new Date().toISOString()
|
updated_at: new Date().toISOString()
|
||||||
}, MY_SAVE);
|
}, MY_SAVE);
|
||||||
|
showSaveIndicator();
|
||||||
|
return;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log('Ошибка сохранения: ' + e.message, 'error');
|
log('Ошибка сохранения API: ' + e.message, 'error');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fallback на localStorage
|
||||||
|
try {
|
||||||
|
localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(myState));
|
||||||
|
showSaveIndicator();
|
||||||
|
} catch (e) {
|
||||||
|
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() {
|
function updateCryptoPrices() {
|
||||||
for (let symbol in cryptos) {
|
for (let symbol in cryptos) {
|
||||||
const change = (Math.random() - 0.5) * 0.1;
|
const change = (Math.random() - 0.5) * 0.1;
|
||||||
cryptos[symbol].change = change;
|
cryptos[symbol].change = change;
|
||||||
cryptos[symbol].price *= (1 + change);
|
cryptos[symbol].price *= (1 + change);
|
||||||
|
if (cryptos[symbol].price < 0.000001) cryptos[symbol].price = 0.000001;
|
||||||
}
|
}
|
||||||
renderCrypto();
|
renderCrypto();
|
||||||
updateUI();
|
updateUI();
|
||||||
@@ -406,19 +491,34 @@
|
|||||||
const crypto = cryptos[symbol];
|
const crypto = cryptos[symbol];
|
||||||
const changeClass = crypto.change >= 0 ? 'up' : 'down';
|
const changeClass = crypto.change >= 0 ? 'up' : 'down';
|
||||||
const changeSign = crypto.change >= 0 ? '+' : '';
|
const changeSign = crypto.change >= 0 ? '+' : '';
|
||||||
|
const canBuy = myState.cash >= crypto.price;
|
||||||
|
const hasPortfolio = myState.portfolio[symbol] > 0;
|
||||||
|
|
||||||
list.innerHTML += `
|
list.innerHTML += `
|
||||||
<div class="crypto-item">
|
<div class="crypto-item">
|
||||||
|
<div class="crypto-header">
|
||||||
<div>
|
<div>
|
||||||
<div class="crypto-name">${symbol}</div>
|
<div class="crypto-name">${symbol}</div>
|
||||||
<div style="font-size: 12px; opacity: 0.7;">${crypto.name}</div>
|
<div style="font-size: 12px; opacity: 0.7;">${crypto.name}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="crypto-price">$${crypto.price.toFixed(2)}</div>
|
|
||||||
<div class="crypto-change ${changeClass}">${changeSign}${(crypto.change * 100).toFixed(2)}%</div>
|
|
||||||
<div>
|
<div>
|
||||||
<button class="btn btn-buy" onclick="buyCrypto('${symbol}')">Купить</button>
|
<span class="crypto-price">$${crypto.price < 1 ? crypto.price.toFixed(6) : crypto.price.toFixed(2)}</span>
|
||||||
<button class="btn btn-sell" onclick="sellCrypto('${symbol}')" ${myState.portfolio[symbol] ? '' : 'disabled'}>Продать</button>
|
<span class="crypto-change ${changeClass}">${changeSign}${(crypto.change * 100).toFixed(2)}%</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="crypto-buttons">
|
||||||
|
<button class="btn btn-buy" onclick="buyCryptoAmount('${symbol}', 100)" ${myState.cash < 100 ? 'disabled' : ''}>Купить на $100</button>
|
||||||
|
<button class="btn btn-buy" onclick="buyCryptoAmount('${symbol}', 1000)" ${myState.cash < 1000 ? 'disabled' : ''}>Купить на $1000</button>
|
||||||
|
<button class="btn btn-buy" onclick="buyCryptoPercent('${symbol}', 0.1)" ${myState.cash < 10 ? 'disabled' : ''}>10%</button>
|
||||||
|
<button class="btn btn-sell" onclick="sellCryptoPercent('${symbol}', 1)" ${!hasPortfolio ? 'disabled' : ''}>Продать всё</button>
|
||||||
|
</div>
|
||||||
|
${hasPortfolio ? `
|
||||||
|
<div style="margin-top: 10px; font-size: 13px; opacity: 0.8;">
|
||||||
|
У вас: ${myState.portfolio[symbol].toFixed(6)} ${symbol}
|
||||||
|
(≈$${(myState.portfolio[symbol] * crypto.price).toFixed(2)})
|
||||||
|
</div>
|
||||||
|
` : ''}
|
||||||
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
renderPortfolio();
|
renderPortfolio();
|
||||||
@@ -430,14 +530,23 @@
|
|||||||
let html = '';
|
let html = '';
|
||||||
for (let symbol in myState.portfolio) {
|
for (let symbol in myState.portfolio) {
|
||||||
const amount = myState.portfolio[symbol];
|
const amount = myState.portfolio[symbol];
|
||||||
|
if (amount < 0.000001) continue;
|
||||||
const value = amount * cryptos[symbol].price;
|
const value = amount * cryptos[symbol].price;
|
||||||
totalValue += value;
|
totalValue += value;
|
||||||
html += `
|
html += `
|
||||||
<div class="crypto-item">
|
<div class="crypto-item">
|
||||||
|
<div class="crypto-header">
|
||||||
<div class="crypto-name">${symbol}</div>
|
<div class="crypto-name">${symbol}</div>
|
||||||
<div>${amount.toFixed(6)}</div>
|
|
||||||
<div class="crypto-price">$${value.toFixed(2)}</div>
|
<div class="crypto-price">$${value.toFixed(2)}</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div style="font-size: 13px; opacity: 0.8;">
|
||||||
|
${amount.toFixed(6)} ${symbol}
|
||||||
|
</div>
|
||||||
|
<button class="btn btn-sell" style="margin-top: 10px; width: 100%;"
|
||||||
|
onclick="sellCryptoPercent('${symbol}', 1)">
|
||||||
|
Продать всё за $${value.toFixed(2)}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
if (html === '') {
|
if (html === '') {
|
||||||
@@ -447,33 +556,43 @@
|
|||||||
document.getElementById('cryptoValue').textContent = '$' + Math.floor(totalValue).toLocaleString();
|
document.getElementById('cryptoValue').textContent = '$' + Math.floor(totalValue).toLocaleString();
|
||||||
}
|
}
|
||||||
|
|
||||||
function buyCrypto(symbol) {
|
// Покупка на указанную сумму в долларах (ИСПРАВЛЕНО!)
|
||||||
const amount = parseFloat(prompt(`Сколько ${symbol} купить? (цена: $${cryptos[symbol].price.toFixed(2)})`));
|
function buyCryptoAmount(symbol, amountUsd) {
|
||||||
if (!amount || amount <= 0) return;
|
const price = cryptos[symbol].price;
|
||||||
const cost = amount * cryptos[symbol].price;
|
if (myState.cash < amountUsd) {
|
||||||
if (myState.cash < cost) {
|
log(`Недостаточно средств (есть $${Math.floor(myState.cash)}, нужно $${amountUsd})`, 'error');
|
||||||
log('Недостаточно средств', 'error');
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
myState.cash -= cost;
|
const amount = amountUsd / price;
|
||||||
|
myState.cash -= amountUsd;
|
||||||
myState.portfolio[symbol] = (myState.portfolio[symbol] || 0) + amount;
|
myState.portfolio[symbol] = (myState.portfolio[symbol] || 0) + amount;
|
||||||
log(`Куплено ${amount} ${symbol} за $${cost.toFixed(2)}`, 'success');
|
log(`Куплено ${amount.toFixed(6)} ${symbol} за $${amountUsd}`, 'success');
|
||||||
|
saveState();
|
||||||
renderCrypto();
|
renderCrypto();
|
||||||
updateUI();
|
updateUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
function sellCrypto(symbol) {
|
// Покупка на процент от денег
|
||||||
const amount = parseFloat(prompt(`Сколько ${symbol} продать? (есть: ${myState.portfolio[symbol]})`));
|
function buyCryptoPercent(symbol, percent) {
|
||||||
if (!amount || amount <= 0) return;
|
const amountUsd = myState.cash * percent;
|
||||||
if (myState.portfolio[symbol] < amount) {
|
buyCryptoAmount(symbol, amountUsd);
|
||||||
log('Недостаточно криптовалюты', 'error');
|
}
|
||||||
|
|
||||||
|
// Продажа процента от криптовалюты
|
||||||
|
function sellCryptoPercent(symbol, percent) {
|
||||||
|
if (!myState.portfolio[symbol] || myState.portfolio[symbol] < 0.000001) {
|
||||||
|
log(`У вас нет ${symbol}`, 'error');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const amount = myState.portfolio[symbol] * percent;
|
||||||
const revenue = amount * cryptos[symbol].price;
|
const revenue = amount * cryptos[symbol].price;
|
||||||
myState.cash += revenue;
|
myState.cash += revenue;
|
||||||
myState.portfolio[symbol] -= amount;
|
myState.portfolio[symbol] -= amount;
|
||||||
if (myState.portfolio[symbol] < 0.000001) delete myState.portfolio[symbol];
|
if (myState.portfolio[symbol] < 0.000001) {
|
||||||
log(`Продано ${amount} ${symbol} за $${revenue.toFixed(2)}`, 'success');
|
delete myState.portfolio[symbol];
|
||||||
|
}
|
||||||
|
log(`Продано ${amount.toFixed(6)} ${symbol} за $${revenue.toFixed(2)}`, 'success');
|
||||||
|
saveState();
|
||||||
renderCrypto();
|
renderCrypto();
|
||||||
updateUI();
|
updateUI();
|
||||||
}
|
}
|
||||||
@@ -482,10 +601,10 @@
|
|||||||
// ПЕРЕВОДЫ
|
// ПЕРЕВОДЫ
|
||||||
// ═══════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════
|
||||||
async function transferFrom(source) {
|
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 input = document.getElementById(source === 'clicker' ? 'fromClicker' : 'fromInvestor');
|
||||||
const amount = parseFloat(input.value);
|
const amount = parseFloat(input.value);
|
||||||
if (!amount || amount <= 0) { log('Введите сумму', 'error'); return; }
|
if (!amount || amount <= 0) { log('Введите корректную сумму', 'error'); return; }
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let sourceTable, sourceSave, sourceKey;
|
let sourceTable, sourceSave, sourceKey;
|
||||||
@@ -509,7 +628,7 @@
|
|||||||
const available = source === 'clicker' ? state.score : state.capital;
|
const available = source === 'clicker' ? state.score : state.capital;
|
||||||
|
|
||||||
if (available < amount) {
|
if (available < amount) {
|
||||||
log('Недостаточно средств в источнике', 'error');
|
log(`Недостаточно средств в источнике (есть ${Math.floor(available)}, нужно ${amount})`, 'error');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -527,8 +646,9 @@
|
|||||||
}, sourceSave, source);
|
}, sourceSave, source);
|
||||||
|
|
||||||
myState.cash += amount;
|
myState.cash += amount;
|
||||||
log(`Получено $${amount} из ${source}`, 'success');
|
log(`Получено $${amount.toLocaleString()} из ${source}`, 'success');
|
||||||
input.value = '';
|
input.value = '';
|
||||||
|
saveState();
|
||||||
updateUI();
|
updateUI();
|
||||||
await refreshAvailable();
|
await refreshAvailable();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -537,11 +657,14 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function transferTo(target) {
|
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 input = document.getElementById(target === 'clicker' ? 'toClicker' : 'toInvestor');
|
||||||
const amount = parseFloat(input.value);
|
const amount = parseFloat(input.value);
|
||||||
if (!amount || amount <= 0) { log('Введите сумму', 'error'); return; }
|
if (!amount || amount <= 0) { log('Введите корректную сумму', 'error'); return; }
|
||||||
if (myState.cash < amount) { log('Недостаточно средств', 'error'); return; }
|
if (myState.cash < amount) {
|
||||||
|
log(`Недостаточно средств (есть $${Math.floor(myState.cash)}, нужно $${amount})`, 'error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let targetTable, targetSave, targetKey;
|
let targetTable, targetSave, targetKey;
|
||||||
@@ -576,8 +699,9 @@
|
|||||||
}, targetSave, target);
|
}, targetSave, target);
|
||||||
|
|
||||||
myState.cash -= amount;
|
myState.cash -= amount;
|
||||||
log(`Отправлено $${amount} в ${target}`, 'success');
|
log(`Отправлено $${amount.toLocaleString()} в ${target}`, 'success');
|
||||||
input.value = '';
|
input.value = '';
|
||||||
|
saveState();
|
||||||
updateUI();
|
updateUI();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log('Ошибка перевода: ' + e.message, 'error');
|
log('Ошибка перевода: ' + e.message, 'error');
|
||||||
@@ -616,12 +740,17 @@
|
|||||||
|
|
||||||
container.innerHTML += `
|
container.innerHTML += `
|
||||||
<div class="construction-stage ${isCompleted ? 'completed' : ''} ${isActive ? 'active' : ''}">
|
<div class="construction-stage ${isCompleted ? 'completed' : ''} ${isActive ? 'active' : ''}">
|
||||||
<div style="display: flex; justify-content: space-between; margin-bottom: 10px;">
|
<div style="display: flex; justify-content: space-between; margin-bottom: 10px; flex-wrap: wrap; gap: 10px;">
|
||||||
<div>
|
<div>
|
||||||
<div style="font-weight: bold; font-size: 16px;">${stage.name}</div>
|
<div style="font-weight: bold; font-size: 16px;">${stage.name}</div>
|
||||||
<div style="font-size: 12px; opacity: 0.7;">Стоимость: $${stage.cost.toLocaleString()} | Время: ${stage.time}с</div>
|
<div style="font-size: 12px; opacity: 0.7;">Стоимость: $${stage.cost.toLocaleString()} | Время: ${stage.time}с</div>
|
||||||
</div>
|
</div>
|
||||||
${isActive ? `<button class="btn btn-action" onclick="buildStage()">Строить</button>` : ''}
|
${isActive && !isCompleted ? `
|
||||||
|
<button class="btn btn-action" onclick="buildStage()"
|
||||||
|
${myState.cash < stage.cost ? 'disabled' : ''}>
|
||||||
|
${myState.house.progress > 0 ? '⚡ Ускорить' : '🏗️ Начать строить'}
|
||||||
|
</button>
|
||||||
|
` : ''}
|
||||||
${isCompleted ? '<div style="color: #4caf50; font-weight: bold;">✓ Готово</div>' : ''}
|
${isCompleted ? '<div style="color: #4caf50; font-weight: bold;">✓ Готово</div>' : ''}
|
||||||
</div>
|
</div>
|
||||||
${isActive ? `
|
${isActive ? `
|
||||||
@@ -641,12 +770,19 @@
|
|||||||
}
|
}
|
||||||
const stage = houseStages[myState.house.stage];
|
const stage = houseStages[myState.house.stage];
|
||||||
if (myState.cash < stage.cost) {
|
if (myState.cash < stage.cost) {
|
||||||
log('Недостаточно средств', 'error');
|
log(`Недостаточно средств (есть $${Math.floor(myState.cash)}, нужно $${stage.cost})`, 'error');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (myState.house.progress === 0) {
|
||||||
myState.cash -= stage.cost;
|
myState.cash -= stage.cost;
|
||||||
|
}
|
||||||
|
myState.house.progress += 10;
|
||||||
|
if (myState.house.progress >= 100) {
|
||||||
|
myState.house.stage++;
|
||||||
myState.house.progress = 0;
|
myState.house.progress = 0;
|
||||||
log(`Начато строительство: ${stage.name}`, 'success');
|
log(`Этап "${stage.name}" завершён!`, 'success');
|
||||||
|
}
|
||||||
|
saveState();
|
||||||
renderHouse();
|
renderHouse();
|
||||||
updateUI();
|
updateUI();
|
||||||
}
|
}
|
||||||
@@ -663,7 +799,10 @@
|
|||||||
<div class="shop-item ${owned ? 'owned' : ''}">
|
<div class="shop-item ${owned ? 'owned' : ''}">
|
||||||
<div class="item-info">
|
<div class="item-info">
|
||||||
<div class="item-name">${biz.name}</div>
|
<div class="item-name">${biz.name}</div>
|
||||||
<div class="item-desc">Доход: $${biz.income}/сек</div>
|
<div class="item-desc">
|
||||||
|
Доход: $${biz.income}/сек
|
||||||
|
${owned ? ` | Работников: ${myState.businesses[biz.id].workers} | Эффективность: x${myState.businesses[biz.id].efficiency.toFixed(1)}` : ''}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="item-price">$${biz.cost.toLocaleString()}</div>
|
<div class="item-price">$${biz.cost.toLocaleString()}</div>
|
||||||
<button class="btn ${owned ? 'btn-action' : 'btn-buy'}"
|
<button class="btn ${owned ? 'btn-action' : 'btn-buy'}"
|
||||||
@@ -679,24 +818,41 @@
|
|||||||
function buyBusiness(id) {
|
function buyBusiness(id) {
|
||||||
const biz = businesses.find(b => b.id === id);
|
const biz = businesses.find(b => b.id === id);
|
||||||
if (myState.cash < biz.cost) {
|
if (myState.cash < biz.cost) {
|
||||||
log('Недостаточно средств', 'error');
|
log(`Недостаточно средств (есть $${Math.floor(myState.cash)}, нужно $${biz.cost})`, 'error');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
myState.cash -= biz.cost;
|
myState.cash -= biz.cost;
|
||||||
myState.businesses[id] = { workers: 1, efficiency: 1 };
|
myState.businesses[id] = { workers: 1, efficiency: 1 };
|
||||||
log(`Куплен бизнес: ${biz.name}`, 'success');
|
log(`Куплен бизнес: ${biz.name}`, 'success');
|
||||||
|
saveState();
|
||||||
renderBusinesses();
|
renderBusinesses();
|
||||||
updateUI();
|
updateUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
function manageBusiness(id) {
|
function manageBusiness(id) {
|
||||||
const biz = businesses.find(b => b.id === id);
|
const biz = businesses.find(b => b.id === id);
|
||||||
const action = prompt(`Управление: ${biz.name}\n1. Нанять работника ($${biz.cost / 10})\n2. Уволить работника\n3. Улучшить эффективность ($${biz.cost / 5})\nВведите номер:`);
|
const hireCost = Math.floor(biz.cost / 10);
|
||||||
|
const upgradeCost = Math.floor(biz.cost / 5);
|
||||||
|
|
||||||
|
const action = prompt(
|
||||||
|
`Управление: ${biz.name}\n\n` +
|
||||||
|
`Текущее состояние:\n` +
|
||||||
|
`- Работников: ${myState.businesses[id].workers}\n` +
|
||||||
|
`- Эффективность: x${myState.businesses[id].efficiency.toFixed(1)}\n` +
|
||||||
|
`- Доход: $${Math.floor(biz.income * myState.businesses[id].workers * myState.businesses[id].efficiency)}/сек\n\n` +
|
||||||
|
`Действия:\n` +
|
||||||
|
`1. Нанять работника ($${hireCost.toLocaleString()})\n` +
|
||||||
|
`2. Уволить работника (бесплатно)\n` +
|
||||||
|
`3. Улучшить эффективность x1.5 ($${upgradeCost.toLocaleString()})\n\n` +
|
||||||
|
`Введите номер действия:`
|
||||||
|
);
|
||||||
|
|
||||||
if (action === '1') {
|
if (action === '1') {
|
||||||
const cost = biz.cost / 10;
|
if (myState.cash < hireCost) {
|
||||||
if (myState.cash < cost) { log('Недостаточно средств', 'error'); return; }
|
log(`Недостаточно средств (нужно $${hireCost})`, 'error');
|
||||||
myState.cash -= cost;
|
return;
|
||||||
|
}
|
||||||
|
myState.cash -= hireCost;
|
||||||
myState.businesses[id].workers++;
|
myState.businesses[id].workers++;
|
||||||
log(`Нанят работник в ${biz.name}`, 'success');
|
log(`Нанят работник в ${biz.name}`, 'success');
|
||||||
} else if (action === '2') {
|
} else if (action === '2') {
|
||||||
@@ -707,12 +863,15 @@
|
|||||||
log('Нельзя уволить последнего работника', 'error');
|
log('Нельзя уволить последнего работника', 'error');
|
||||||
}
|
}
|
||||||
} else if (action === '3') {
|
} else if (action === '3') {
|
||||||
const cost = biz.cost / 5;
|
if (myState.cash < upgradeCost) {
|
||||||
if (myState.cash < cost) { log('Недостаточно средств', 'error'); return; }
|
log(`Недостаточно средств (нужно $${upgradeCost})`, 'error');
|
||||||
myState.cash -= cost;
|
return;
|
||||||
myState.businesses[id].efficiency *= 1.5;
|
|
||||||
log(`Улучшена эффективность ${biz.name}`, 'success');
|
|
||||||
}
|
}
|
||||||
|
myState.cash -= upgradeCost;
|
||||||
|
myState.businesses[id].efficiency *= 1.5;
|
||||||
|
log(`Улучшена эффективность ${biz.name} до x${myState.businesses[id].efficiency.toFixed(1)}`, 'success');
|
||||||
|
}
|
||||||
|
saveState();
|
||||||
renderBusinesses();
|
renderBusinesses();
|
||||||
updateUI();
|
updateUI();
|
||||||
}
|
}
|
||||||
@@ -744,13 +903,18 @@
|
|||||||
|
|
||||||
function buyLuxury(id) {
|
function buyLuxury(id) {
|
||||||
const item = luxuryItems.find(i => i.id === id);
|
const item = luxuryItems.find(i => i.id === id);
|
||||||
|
if (myState.luxury[id]) {
|
||||||
|
log('У вас уже есть этот предмет', 'error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (myState.cash < item.cost) {
|
if (myState.cash < item.cost) {
|
||||||
log('Недостаточно средств', 'error');
|
log(`Недостаточно средств (есть $${Math.floor(myState.cash)}, нужно $${item.cost})`, 'error');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
myState.cash -= item.cost;
|
myState.cash -= item.cost;
|
||||||
myState.luxury[id] = true;
|
myState.luxury[id] = true;
|
||||||
log(`Куплено: ${item.name}`, 'success');
|
log(`Куплено: ${item.name}`, 'success');
|
||||||
|
saveState();
|
||||||
renderLuxury();
|
renderLuxury();
|
||||||
updateUI();
|
updateUI();
|
||||||
}
|
}
|
||||||
@@ -759,7 +923,6 @@
|
|||||||
// ИГРОВОЙ ЦИКЛ
|
// ИГРОВОЙ ЦИКЛ
|
||||||
// ═══════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════
|
||||||
function tick() {
|
function tick() {
|
||||||
// Доход от бизнесов
|
|
||||||
let totalIncome = 0;
|
let totalIncome = 0;
|
||||||
for (let id in myState.businesses) {
|
for (let id in myState.businesses) {
|
||||||
const biz = businesses.find(b => b.id === id);
|
const biz = businesses.find(b => b.id === id);
|
||||||
@@ -771,7 +934,6 @@
|
|||||||
myState.cash += totalIncome;
|
myState.cash += totalIncome;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Строительство дома
|
|
||||||
if (myState.house.stage < houseStages.length && myState.house.progress > 0) {
|
if (myState.house.stage < houseStages.length && myState.house.progress > 0) {
|
||||||
const stage = houseStages[myState.house.stage];
|
const stage = houseStages[myState.house.stage];
|
||||||
myState.house.progress += (100 / stage.time);
|
myState.house.progress += (100 / stage.time);
|
||||||
|
|||||||
Reference in New Issue
Block a user