[html]<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Èãðîâîé àâòîìàò</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
body {
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
padding: 20px;
color: #fff;
}
.unified-container {
display: flex;
width: 100%;
max-width: 1200px;
background: rgba(30, 30, 46, 0.9);
border-radius: 20px;
border: 3px solid #4a4a6d;
box-shadow: 0 0 40px rgba(0, 0, 0, 0.7);
overflow: hidden;
}
.top-players {
flex: 0 0 250px;
background: rgba(40, 40, 60, 0.9);
padding: 15px;
overflow-y: auto;
border-right: 2px solid #5a5a80;
}
.top-players h2 {
position: sticky;
top: 0;
background: rgba(40, 40, 60, 0.95);
padding-bottom: 10px;
z-index: 10;
}
.player-list { list-style: none; padding-top: 5px; }
.player-item { display: flex; justify-content: space-between; padding: 10px 5px; margin-bottom: 5px; background: rgba(50, 50, 70, 0.6); border-radius: 6px; border-left: 3px solid #ffd700; font-size: 14px; transition: background 0.2s; }
.player-item:hover { background: rgba(60, 60, 80, 0.7); }
.player-item.user-highlight { border-left: 3px solid #4CAF50; background: rgba(76, 175, 80, 0.1); }
.right-section {
flex-grow: 1;
display: flex;
flex-direction: column;
padding: 20px;
align-items: center;
}
.slot-machine-container {
width: 100%;
max-width: 500px;
display: flex;
flex-direction: column;
align-items: center;
}
.header-controls {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
margin-bottom: 15px;
gap: 15px;
}
.coins-display {
display: flex;
align-items: center;
gap: 10px;
background: rgba(30, 30, 46, 0.8);
padding: 10px 15px;
border-radius: 10px;
border: 2px solid #FFD700;
box-shadow: 0 0 15px rgba(255, 215, 0, 0.3);
flex: 1;
}
.coins-info {
display: flex;
flex-direction: column;
gap: 5px;
}
.coins-count {
font-size: 24px;
font-weight: bold;
color: #FFD700;
text-shadow: 0 0 10px rgba(255, 215, 0, 0.5);
}
.coins-label {
font-size: 14px;
color: #aaa;
}
.daily-coins-btn {
background: linear-gradient(145deg, #FFD700, #FFA500);
color: #000;
border: none;
border-radius: 8px;
padding: 8px 15px;
font-size: 14px;
font-weight: bold;
cursor: pointer;
transition: all 0.3s ease;
white-space: nowrap;
}
.daily-coins-btn:hover:not(:disabled) {
background: linear-gradient(145deg, #FFA500, #FFD700);
transform: scale(1.05);
}
.daily-coins-btn:disabled {
background: #4a4a6d;
color: #888;
cursor: not-allowed;
}
.timer-container {
background: rgba(30, 30, 46, 0.8);
padding: 10px 15px;
border-radius: 10px;
border: 2px solid #4a4a6d;
box-shadow: 0 0 15px rgba(0, 0, 0, 0.4);
flex: 1;
text-align: center;
}
#slot-timer {
font-size: 16px;
color: #ffdd8a;
font-weight: bold;
text-shadow: 0 0 5px rgba(255, 221, 138, 0.7);
}
.spin-controls {
display: flex;
flex-direction: column;
align-items: center;
margin-top: 15px;
gap: 10px;
}
.checkbox-container {
padding: 8px 12px;
align-self: flex-start;
margin-left: 20px;
}
#slot-spin {
width: 90%;
max-width: 300px;
height: 60px;
font-size: 28px;
font-weight: bold;
color: #fff;
background: linear-gradient(145deg, #ff416c, #ff4b2b);
border: none;
border-radius: 12px;
cursor: pointer;
box-shadow: 0 10px 20px rgba(255, 75, 43, 0.6), 0 0 0 4px #ffc107;
transition: all 0.2s ease;
text-transform: uppercase;
}
#slot-spin:hover:not(:disabled) {
background: linear-gradient(145deg, #ff4b2b, #ff416c);
transform: scale(1.03);
box-shadow: 0 12px 25px rgba(255, 75, 43, 0.8), 0 0 0 6px #ffd700;
}
#slot-spin:disabled {
background: #4a4a6d;
cursor: not-allowed;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
opacity: 0.7;
}
#toggle-stats-btn {
background: linear-gradient(to right, #4a4a6d, #5a5a80);
color: #fff;
border: none;
border-radius: 8px;
padding: 10px 15px;
font-size: 14px;
cursor: pointer;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3);
transition: background 0.3s ease, transform 0.2s ease;
margin-top: 20px;
display: flex;
align-items: center;
gap: 8px;
width: 90%;
max-width: 500px;
justify-content: center;
}
#toggle-stats-btn:hover {
background: linear-gradient(to right, #5a5a80, #6a6a90);
transform: translateY(-2px);
}
.player-info {
background: rgba(30, 30, 46, 0.8);
border-radius: 15px;
padding: 15px;
border: 2px solid #6a6a90;
box-shadow: 0 0 15px rgba(0, 0, 0, 0.5);
width: 90%;
max-width: 500px;
max-height: 0;
overflow: hidden;
opacity: 0;
padding-top: 0;
padding-bottom: 0;
margin-top: 10px;
transition: max-height 0.5s ease-in-out, opacity 0.4s ease, padding 0.5s ease;
}
.player-info.open {
max-height: 500px;
opacity: 1;
padding-top: 15px;
padding-bottom: 15px;
}
.top-players h2, .player-info h2 {
text-align: center; margin-bottom: 15px; color: #ffd700; text-shadow: 0 0 10px rgba(255, 215, 0, 0.5); font-size: 20px;
}
.player-name { font-weight: bold; }
.player-amount { color: #4CAF50; font-weight: bold; }
.slot-machine { width: 100%; padding: 15px; background: rgba(40, 40, 60, 0.9); border-radius: 10px; text-align: center; color: #fff; border: 2px solid #5a5a80; box-shadow: 0 0 25px rgba(0, 0, 0, 0.4); position: relative; }
.result-display { padding: 10px; margin-bottom: 15px; font-size: 16px; min-height: 50px; display: flex; align-items: center; justify-content: center; transition: all 0.5s ease; }
.win-result { background: rgba(76, 175, 80, 0.2); color: #4CAF50; border: 2px solid #4CAF50; box-shadow: 0 0 15px rgba(76, 175, 80, 0.5); text-shadow: 0 0 5px rgba(76, 175, 80, 0.7); }
.lose-result { background: rgba(244, 67, 54, 0.2); color: #f44336; border: 2px solid #f44336; box-shadow: 0 0 15px rgba(244, 67, 54, 0.3); }
.slot-window { display: flex; justify-content: space-around; margin-bottom: 15px; padding: 10px; border-radius: 10px; border: 2px solid #555; background: rgba(20, 20, 35, 0.8);}
.slot-reel { width: 80px; height: 80px; overflow: hidden; border-radius: 8px; background: #000; border: 2px solid #555; position: relative; box-shadow: inset 0 0 8px rgba(0, 0, 0, 0.7); }
.slot-reel img { width: 100%; height: 100%; object-fit: contain; top: 0; transition: top 0.15s linear; }
.current-player {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15px;
background: rgba(40, 40, 60, 0.7);
border-radius: 10px;
border-left: 4px solid #4CAF50;
margin-bottom: 15px;
}
.player-resources {
display: flex;
flex-direction: column;
gap: 5px;
align-items: flex-end;
}
.player-coins {
color: #FFD700;
font-weight: bold;
font-size: 18px;
}
.player-stats { display: flex; flex-direction: column; gap: 10px; }
.stat-item { display: flex; justify-content: space-between; padding: 10px 12px; background: rgba(50, 50, 70, 0.5); border-radius: 6px; }
.stat-label { color: #ccc; }
.stat-value { color: #ffd700; font-weight: bold; }
.last-spin-result {
background: rgba(90, 90, 128, 0.3);
border: 1px solid #6a6a90;
border-radius: 8px;
padding: 10px;
margin-bottom: 10px;
font-size: 14px;
}
.last-spin-win { color: #4CAF50; border-color: #4CAF50; background: rgba(76, 175, 80, 0.1); }
.last-spin-lose { color: #f44336; border-color: #f44336; background: rgba(244, 67, 54, 0.1); }
.daily-coins-timer {
font-size: 12px;
margin-top: 5px;
padding: 4px 8px;
border-radius: 4px;
font-weight: bold;
text-align: center;
}
.daily-coins-timer.available {
background: rgba(76, 175, 80, 0.2);
color: #4CAF50;
border: 1px solid #4CAF50;
}
.daily-coins-timer.cooldown {
background: rgba(244, 67, 54, 0.2);
color: #f44336;
border: 1px solid #f44336;
}
.coins-section {
display: flex;
flex-direction: column;
gap: 5px;
}
@media (max-width: 850px) {
.unified-container {
flex-direction: column;
max-width: 550px;
}
.top-players {
flex: none;
width: 100%;
max-height: 250px;
border-right: none;
border-bottom: 2px solid #5a5a80;
border-radius: 20px 20px 0 0;
}
.right-section {
padding: 15px;
}
.top-players h2 {
position: static;
background: none;
}
.slot-machine-container {
max-width: none;
}
.player-info {
max-width: none;
}
#toggle-stats-btn {
max-width: none;
}
.current-player {
flex-direction: column;
gap: 10px;
align-items: stretch;
}
.player-resources {
align-items: stretch;
}
.header-controls {
flex-direction: column;
}
.coins-display, .timer-container {
width: 100%;
}
}
</style>
</head>
<body>
<div class="unified-container">
<div class="top-players">
<h2>ÒÎÏ ÈÃÐÎÊÎÂ</h2>
<ul class="player-list" id="top-players-list">
<li class="player-item"><span class="player-name">Çàãðóçêà...</span><span class="player-amount">0$</span></li>
</ul>
</div>
<div class="right-section">
<div class="slot-machine-container">
<div class="header-controls">
<div class="coins-display">
<div class="coins-info">
<div class="coins-count" id="coins-count">0 🪙</div>
<div class="coins-label">Âàøè æåòîíû</div>
<div id="daily-coins-timer" class="daily-coins-timer available">
Ìîæíî ïîëó÷èòü!
</div>
</div>
<button id="daily-coins-btn" class="daily-coins-btn" title="Ïîëó÷èòü åæåäíåâíûå æåòîíû">
🎁 Ïîëó÷èòü
</button>
</div>
<div class="timer-container">
<div id="slot-timer">Ìîæåøü êðóòèòü! ✅</div>
</div>
</div>
<div class="slot-machine">
<div id="result-display" class="result-display">
Äîáðî ïîæàëîâàòü! Æìè SPIN, èñïûòàé óäà÷ó!
</div>
<div class="slot-window">
<div class="slot-reel"><img src="https://upforme.ru/uploads/001c/52/b6/2/605998.png" alt="Symbol"></div>
<div class="slot-reel"><img src="https://upforme.ru/uploads/001c/52/b6/2/319417.png" alt="Symbol"></div>
<div class="slot-reel"><img src="https://upforme.ru/uploads/001c/52/b6/2/802623.png" alt="Symbol"></div>
</div>
<div class="spin-controls">
<div class="checkbox-container">
<input type="checkbox" id="confirm-bet">
<label for="confirm-bet">ïîäòâåðæäàþ ñòîèìîñòü ñòàâêè</label>
</div>
<button id="slot-spin" disabled>SPIN</button>
</div>
</div>
</div>
<button id="toggle-stats-btn">
<span>Ïîêàçàòü/Ñêðûòü ñòàòèñòèêó èãðîêà</span>
<span class="arrow">▼</span>
</button>
<div class="player-info" id="player-stats-block">
<h2>Âàøà ñòàòèñòèêà</h2>
<div class="current-player">
<span class="player-name" id="player-nickname">Çàãðóçêà...</span>
<div class="player-resources">
<span class="player-amount" id="player-balance">0$</span>
<span class="player-coins" id="player-coins">0 🪙</span>
</div>
</div>
<div class="last-spin-result" id="last-spin-result">
Ïîñëåäíèé ñïèí: íå áûëî
</div>
<div class="player-stats">
<div class="stat-item">
<span class="stat-label">Âñåãî èãð:</span>
<span class="stat-value" id="total-games">0</span>
</div>
<div class="stat-item">
<span class="stat-label">Ïîáåä:</span>
<span class="stat-value" id="wins">0</span>
</div>
<div class="stat-item">
<span class="stat-label">Ïðîöåíò ïîáåä:</span>
<span class="stat-value" id="win-rate">0%</span>
</div>
<div class="stat-item">
<span class="stat-label">Îáùèé âûèãðûø:</span>
<span class="stat-value" id="total-winnings">0$</span>
</div>
<div class="stat-item">
<span class="stat-label">Òåêóùàÿ ñåðèÿ:</span>
<span class="stat-value" id="current-streak">0</span>
</div>
<div class="stat-item">
<span class="stat-label">Ëó÷øàÿ ñåðèÿ:</span>
<span class="stat-value" id="best-streak">0</span>
</div>
</div>
</div>
</div>
</div>
<script>
// JavaScript êîä áóäåò âñòàâëåí çäåñü
(function(){
// Ïåðåêëþ÷åíèå ñòàòèñòèêè
const statsBlock = document.getElementById('player-stats-block');
const toggleBtn = document.getElementById('toggle-stats-btn');
toggleBtn.addEventListener('click', () => {
statsBlock.classList.toggle('open');
});
console.log('🎮 Frame script starting...');
// Êîíñòàíòû
const EVERYDAY_COINS = 1; // Êîëè÷åñòâî æåòîíîâ, âûäàâàåìûõ åæåäíåâíî
const COINS_PER_SPIN = 1; // Êîëè÷åñòâî æåòîíîâ äëÿ îäíîãî ñïèíà
// Ôóíêöèÿ îòïðàâêè ñîîáùåíèé - îòïðàâëÿåì â ðîäèòåëüñêîå îêíî (wildcard)
function sendToParent(data) {
try {
console.log('📤 Sending to parent:', data.type);
// '*' îçíà÷àåò îòïðàâêó íà ëþáîé origin ðîäèòåëüñêîãî îêíà
window.parent.postMessage(data, '*');
return true;
} catch (e) {
console.error('❌ Send failed:', e);
return false;
}
}
// Ôóíêöèÿ çàïðîñîâ ê õðàíèëèùó
function sendStorageRequest(action, data = {}) {
return new Promise((resolve, reject) => {
const requestId = Date.now() + '_' + Math.random().toString(36).substr(2, 9);
const message = {
_slotMachine: true,
type: "storageRequest",
requestId: requestId,
action: action,
...data
};
const responseHandler = (event) => {
// Ïðèíèìàåì ñîîáùåíèÿ îò ëþáîãî origin (íî òîëüêî îò ðîäèòåëÿ)
const response = event.data;
if (response && response._slotMachine === true &&
response.type === "storageResponse" &&
response.requestId === requestId) {
console.log('📨 Received response from parent:', action);
window.removeEventListener("message", responseHandler);
clearTimeout(timeout);
if (response.error) {
reject(new Error(response.error));
} else {
resolve(response.data);
}
}
};
window.addEventListener("message", responseHandler);
const timeout = setTimeout(() => {
window.removeEventListener("message", responseHandler);
console.error('⏰ Timeout for action:', action);
reject(new Error(`Timeout: ${action}`));
}, 8000);
if (!sendToParent(message)) {
window.removeEventListener("message", responseHandler);
clearTimeout(timeout);
reject(new Error("Failed to send message to parent"));
}
});
}
// Çàãðóçêà äàííûõ ïîëüçîâàòåëÿ
async function loadUserData() {
try {
console.log('👤 Loading user data...');
const userData = await sendStorageRequest("getUserData");
console.log('📊 User data received:', userData);
if (!userData) {
throw new Error("Äàííûå ïîëüçîâàòåëÿ íå ïîëó÷åíû");
}
// Èíèöèàëèçàöèÿ âñåõ ïîëåé
return {
userId: userData.userId || "unknown",
nickname: userData.nickname || "Èãðîê",
balance: typeof userData.balance === 'number' ? userData.balance : 0,
coins: typeof userData.coins === 'number' ? userData.coins : 0, // Æåòîíû
lastDailyCoins: userData.lastDailyCoins || null, // Äàòà ïîñëåäíåãî ïîëó÷åíèÿ æåòîíîâ
totalGames: userData.totalGames || 0,
wins: userData.wins || 0,
totalWinnings: userData.totalWinnings || 0,
maxWin: userData.maxWin || 0,
currentStreak: userData.currentStreak || 0,
bestStreak: userData.bestStreak || 0,
lastSpin: userData.lastSpin || null,
lastSpinResult: userData.lastSpinResult || null
};
} catch (error) {
console.error("❌ Error loading user data:", error);
return {
userId: "unknown",
nickname: "Èãðîê",
balance: 0,
coins: 0,
lastDailyCoins: null,
totalGames: 0,
wins: 0,
totalWinnings: 0,
maxWin: 0,
currentStreak: 0,
bestStreak: 0,
lastSpin: null,
lastSpinResult: null
};
}
}
// Ñîõðàíåíèå äàííûõ ïîëüçîâàòåëÿ
async function saveUserData(userData) {
try {
console.log('💾 Saving user data...');
await sendStorageRequest("saveUserData", { userData });
console.log('✅ User data saved');
} catch (error) {
console.error("❌ Error saving user data:", error);
}
}
// Ïîëó÷åíèå åæåäíåâíûõ æåòîíîâ
async function claimDailyCoins() {
try {
console.log('🪙 Claiming daily coins...');
const result = await sendStorageRequest("claimDailyCoins", {
coinsAmount: EVERYDAY_COINS
});
console.log('✅ Daily coins claimed:', result);
return result;
} catch (error) {
console.error("❌ Error claiming daily coins:", error);
throw error;
}
}
// Çàãðóçêà òîïà èãðîêîâ
async function loadTopPlayers() {
try {
console.log('🏆 Loading top players...');
const topPlayers = await sendStorageRequest("getTopPlayers");
console.log('📊 Top players received:', topPlayers?.length || 0, 'players');
return topPlayers || [];
} catch (error) {
console.error("❌ Error loading top players:", error);
return [];
}
}
// Îáíîâëåíèå òîïà èãðîêîâ
async function updateTopPlayers() {
try {
const topPlayers = await loadTopPlayers();
const topList = document.getElementById('top-players-list');
if (!topList) return;
if (topPlayers.length === 0) {
topList.innerHTML = '<li class="player-item"><span class="player-name">Íåò äàííûõ</span><span class="player-amount">0$</span></li>';
return;
}
topList.innerHTML = '';
topPlayers.forEach((player, index) => {
const li = document.createElement('li');
li.className = 'player-item';
if (userData && player.userId === userData.userId) {
li.classList.add('user-highlight');
}
li.innerHTML = `
<span class="player-name">${index + 1}. ${player.nickname || 'Èãðîê'}</span>
<span class="player-amount">${player.totalWinnings || 0}$</span>
`;
topList.appendChild(li);
});
} catch (error) {
console.error('❌ Error updating top players:', error);
}
}
// Èãðîâûå êîíñòàíòû
const TIMER_HOURS = 0;
const TIMER_MINUTES = 0;
const COOLDOWN = (TIMER_HOURS*60 + TIMER_MINUTES)*60*1000;
const symbols = [
{name:"Tikva", url:"https://upforme.ru/uploads/001c/52/b6/2/605998.png"},
{name:"Cherep", url:"https://upforme.ru/uploads/001c/52/b6/2/319417.png"},
{name:"Potion", url:"https://upforme.ru/uploads/001c/52/b6/2/610070.png"}
];
const winningCombos = {
"Tikva,Tikva,Tikva": 100,
"Cherep,Cherep,Cherep": 150,
"Tikva,Cherep,Tikva": 200,
"Potion,Potion,Cherep": 250,
"Potion,Potion,Potion": 300,
"Tikva,Cherep,Potion": 500
};
const reels = document.querySelectorAll(".slot-reel img");
const spinBtn = document.getElementById("slot-spin");
const timerEl = document.getElementById("slot-timer");
const resultDisplay = document.getElementById("result-display");
const confirmBet = document.getElementById("confirm-bet");
const coinsCountEl = document.getElementById("coins-count");
const dailyCoinsBtn = document.getElementById("daily-coins-btn");
const dailyCoinsTimerEl = document.getElementById("daily-coins-timer");
let userData = null;
let debugMode = false; // Ôëàã äëÿ îòëàäêè
// Ïîëó÷åíèå Ìîñêîâñêîãî âðåìåíè (UTC+3)
function getMoscowTime() {
const now = new Date();
// Ìîñêâà UTC+3
return new Date(now.getTime() + (3 * 60 * 60 * 1000));
}
// Ïîëó÷åíèå íà÷àëà òåêóùèõ ñóòîê ïî Ìîñêâå (00:00)
function getStartOfTodayMoscow() {
const moscowTime = getMoscowTime();
return new Date(moscowTime.getFullYear(), moscowTime.getMonth(), moscowTime.getDate()).getTime();
}
// Ïðîâåðêà, ìîæíî ëè ïîëó÷èòü åæåäíåâíûå æåòîíû
function canClaimDailyCoins() {
if (!userData || !userData.lastDailyCoins) return true;
const lastClaimTime = userData.lastDailyCoins;
const todayStart = getStartOfTodayMoscow();
return lastClaimTime < todayStart;
}
// Ôîðìàòèðîâàíèå âðåìåíè äî ñëåäóþùåãî ïîëó÷åíèÿ æåòîíîâ
function getTimeUntilNextClaim() {
if (!userData || !userData.lastDailyCoins) return null;
const moscowTime = getMoscowTime();
const nextClaim = new Date(moscowTime.getFullYear(), moscowTime.getMonth(), moscowTime.getDate() + 1).getTime();
return nextClaim - moscowTime.getTime();
}
// Îáíîâëåíèå èíôîðìàöèè î ïîëüçîâàòåëå
function updateUserInfo() {
if (!userData) {
if (debugMode) console.log('⚠️ No user data to update UI');
return;
}
if (debugMode) console.log('🔄 Updating UI with balance:', userData.balance, 'coins:', userData.coins);
const playerNickname = document.getElementById('player-nickname');
const playerBalance = document.getElementById('player-balance');
const playerCoins = document.getElementById('player-coins');
const totalGames = document.getElementById('total-games');
const wins = document.getElementById('wins');
const totalWinnings = document.getElementById('total-winnings');
const winRate = document.getElementById('win-rate');
const currentStreak = document.getElementById('current-streak');
const bestStreak = document.getElementById('best-streak');
const lastSpinEl = document.getElementById('last-spin-result');
// Îñíîâíàÿ èíôîðìàöèÿ
if (playerNickname) playerNickname.textContent = userData.nickname;
if (playerBalance) playerBalance.textContent = userData.balance + '$';
if (playerCoins) playerCoins.textContent = userData.coins + ' 🪙';
if (coinsCountEl) coinsCountEl.textContent = userData.coins + ' 🪙';
// Ñòàòèñòèêà
if (totalGames) totalGames.textContent = userData.totalGames;
if (wins) wins.textContent = userData.wins;
if (totalWinnings) totalWinnings.textContent = userData.totalWinnings + '$';
if (winRate) {
winRate.textContent = userData.totalGames > 0 ?
Math.round((userData.wins / userData.totalGames) * 100) + '%' : '0%';
}
if (currentStreak) currentStreak.textContent = userData.currentStreak;
if (bestStreak) bestStreak.textContent = userData.bestStreak;
// Ïîñëåäíèé ñïèí
if (lastSpinEl) {
if (userData.lastSpinResult) {
lastSpinEl.textContent = `Ïîñëåäíèé ñïèí: ${userData.lastSpinResult}`;
lastSpinEl.className = userData.lastSpinResult.includes('ÏÎÁÅÄÀ') ?
'last-spin-result last-spin-win' : 'last-spin-result last-spin-lose';
} else {
lastSpinEl.textContent = 'Ïîñëåäíèé ñïèí: íå áûëî';
lastSpinEl.className = 'last-spin-result';
}
}
// Îáíîâëÿåì êíîïêó ïîëó÷åíèÿ æåòîíîâ è òàéìåð
updateDailyCoinsUI();
if (debugMode) console.log('✅ UI updated, balance:', userData.balance + '$, coins:', userData.coins);
}
// Îáíîâëåíèå UI êíîïêè ïîëó÷åíèÿ æåòîíîâ
function updateDailyCoinsUI() {
if (!dailyCoinsBtn || !dailyCoinsTimerEl) return;
const canClaim = canClaimDailyCoins();
dailyCoinsBtn.disabled = !canClaim;
if (canClaim) {
dailyCoinsBtn.title = `Ïîëó÷èòü ${EVERYDAY_COINS} æåòîí${EVERYDAY_COINS > 1 ? 'à' : ''}`;
dailyCoinsTimerEl.textContent = 'Ìîæíî ïîëó÷èòü!';
dailyCoinsTimerEl.className = 'daily-coins-timer available';
} else {
const timeLeft = getTimeUntilNextClaim();
if (timeLeft) {
const hours = Math.floor(timeLeft / (1000 * 60 * 60));
const minutes = Math.floor((timeLeft % (1000 * 60 * 60)) / (1000 * 60));
const seconds = Math.floor((timeLeft % (1000 * 60)) / 1000);
dailyCoinsTimerEl.textContent = `÷åðåç ${hours}÷ ${minutes}ì`;
dailyCoinsTimerEl.className = 'daily-coins-timer cooldown';
dailyCoinsBtn.title = `Ñëåäóþùèå æåòîíû ÷åðåç ${hours}÷ ${minutes}ì`;
}
}
}
// Îáíîâëåíèå ñîñòîÿíèÿ êíîïêè ñïèíà (ó÷èòûâàÿ æåòîíû)
function updateSpinButton() {
if (!userData || !confirmBet || !spinBtn) {
if (debugMode) console.log('⚠️ Missing elements for spin button update');
return;
}
const hasCooldown = userData.lastSpin && (Date.now() - userData.lastSpin < COOLDOWN);
const hasCoins = userData.coins >= COINS_PER_SPIN;
spinBtn.disabled = !confirmBet.checked || hasCooldown || !hasCoins;
// Îáíîâëÿåì òåêñò êíîïêè
if (spinBtn) {
if (!hasCoins) {
spinBtn.textContent = `Íóæíî ${COINS_PER_SPIN} æåòîí${COINS_PER_SPIN > 1 ? 'à' : ''}`;
} else if (hasCooldown) {
spinBtn.textContent = "ÆÄÈ";
} else {
spinBtn.textContent = `SPIN (${COINS_PER_SPIN} æåòîí${COINS_PER_SPIN > 1 ? 'à' : ''})`;
}
}
// Ëîãèðóåì ÒÎËÜÊÎ ïðè èçìåíåíèè ñîñòîÿíèÿ èëè â debug ðåæèìå
if (debugMode) {
console.log('🎮 Spin button state:', {
checked: confirmBet.checked,
hasCooldown: hasCooldown,
hasCoins: hasCoins,
coins: userData.coins,
disabled: spinBtn.disabled
});
}
}
// Îáíîâëåíèå òàéìåðà
function updateTimer() {
if (!userData || !timerEl) return;
if (!userData.lastSpin) {
timerEl.textContent = "Ìîæåøü êðóòèòü! ✅";
updateSpinButton();
return;
}
let diff = COOLDOWN - (Date.now() - userData.lastSpin);
if(diff <= 0){
timerEl.textContent = "Ìîæåøü êðóòèòü! ✅";
updateSpinButton();
} else {
let h=Math.floor(diff/3600000),
m=Math.floor((diff%3600000)/60000),
s=Math.floor((diff%60000)/1000);
timerEl.textContent = `${h}÷ ${m}ì ${s}ñ`;
updateSpinButton();
}
}
// Îáíîâëåíèå òàéìåðà åæåäíåâíûõ æåòîíîâ
function updateDailyCoinsTimer() {
updateDailyCoinsUI();
}
// Ôóíêöèÿ äëÿ ñîçäàíèÿ HTML ðåçóëüòàòà
function createSlotResultHTML(resultSymbols, isWin, winAmount, resultMessage) {
const symbolsHTML = resultSymbols.map(symbolName => {
const symbol = symbols.find(s => s.name === symbolName);
if (symbol) {
return `<div style="width:80px;height:80px;border-radius:10px;border:2px solid #555;background:#000;overflow:hidden;box-shadow:0 0 10px rgba(0,0,0,0.5);margin:0 5px;"><img src="${symbol.url}" alt="${symbolName}" style="width:100%;height:100%;object-fit:contain;"></div>`;
}
return '';
}).join('');
const winStyle = isWin ?
"background:rgba(76,175,80,0.2);color:#4CAF50;border:2px solid #4CAF50;box-shadow:0 0 20px rgba(76,175,80,0.5);text-shadow:0 0 5px rgba(76,175,80,0.7)" :
"background:rgba(244,67,54,0.2);color:#f44336;border:2px solid #f44336;box-shadow:0 0 20px rgba(244,67,54,0.3)";
return `
<div style="background:rgba(30,30,46,0.95);border:2px solid #5a5a80;border-radius:15px;padding:15px;margin:10px 0;max-width:500px;box-shadow:0 0 25px rgba(0,0,0,0.6);">
<div style="text-align:center;margin-bottom:15px;color:#ffd700;text-shadow:0 0 10px rgba(255,215,0,0.5);font-size:20px;border-bottom:2px solid #4a4a6d;padding-bottom:10px;">
🎰 Ðåçóëüòàò ñëîòà
</div>
<div style="display:flex;flex-direction:column;align-items:center;gap:15px;">
<div style="display:flex;justify-content:center;gap:15px;margin-bottom:15px;">
${symbolsHTML}
</div>
<div style="text-align:center;padding:12px;border-radius:10px;font-size:18px;font-weight:bold;width:100%;${winStyle}">
${resultMessage}
</div>
<div style="text-align:center;margin-top:10px;font-size:14px;color:#aaa;border-top:1px solid #4a4a6d;padding-top:10px;">
Èãðîê: <strong style="color:#ffd700;">${userData.nickname}</strong> |
Áàëàíñ: <strong style="color:#4CAF50;">${userData.balance}$</strong> |
Æåòîíû: <strong style="color:#FFD700;">${userData.coins} 🪙</strong>
</div>
</div>
</div>`;
}
// Ôóíêöèÿ âðàùåíèÿ áàðàáàíîâ
async function spinReels() {
if(!userData || !confirmBet || !resultDisplay || !spinBtn) {
console.error('❌ Missing elements for spin');
return;
}
if(!confirmBet.checked) {
resultDisplay.textContent = "Ïîäòâåðäèòå ñòîèìîñòü ñòàâêè!";
resultDisplay.className = "result-display lose-result";
return;
}
if(userData.lastSpin && Date.now() - userData.lastSpin < COOLDOWN){
const timeLeft = COOLDOWN - (Date.now() - userData.lastSpin);
const minutes = Math.floor(timeLeft / 60000);
const seconds = Math.floor((timeLeft % 60000) / 1000);
resultDisplay.textContent = `Ïîäîæäè åù¸ ${minutes}ì ${seconds}ñ!`;
resultDisplay.className = "result-display lose-result";
return;
}
if(userData.coins < COINS_PER_SPIN) {
resultDisplay.textContent = `Íåäîñòàòî÷íî æåòîíîâ! Íóæíî ${COINS_PER_SPIN}`;
resultDisplay.className = "result-display lose-result";
return;
}
spinBtn.disabled=true;
resultDisplay.textContent = "Êðóòèì...";
resultDisplay.className = "result-display";
// Ñïèñûâàåì æåòîíû
userData.coins -= COINS_PER_SPIN;
console.log(`🪙 Spent ${COINS_PER_SPIN} coin(s), remaining: ${userData.coins}`);
let results=[];
let durations=[1000, 1300, 1600];
reels.forEach((img,index)=>{
let cycles = 12 + Math.floor(Math.random()*8);
let finalSymbol = symbols[Math.floor(Math.random()*symbols.length)];
results.push(finalSymbol.name);
let step=0;
let interval = setInterval(()=>{
let sym = symbols[Math.floor(Math.random()*symbols.length)];
img.style.top="-100%";
img.src = sym.url;
setTimeout(()=>{
img.style.top="0";
}, 10);
step++;
if(step>=cycles){
img.src = finalSymbol.url;
img.style.top="0";
clearInterval(interval);
}
}, durations[index]/cycles);
});
setTimeout(async () => {
let reward = 0;
const key = results.join(",");
console.log('🎯 Spin result:', key);
for(let combo in winningCombos){
if(key === combo) {
reward = winningCombos[combo];
console.log('🎉 Winning combo found:', combo, 'reward:', reward);
}
}
let resultMessage = "";
let isWin = false;
if(reward > 0) {
isWin = true;
resultMessage = `ÏÎÁÅÄÀ! Òû âûèãðàë ${reward}$`;
resultDisplay.textContent = resultMessage;
resultDisplay.className = "result-display win-result";
userData.balance += reward;
userData.totalGames += 1;
userData.wins += 1;
userData.totalWinnings += reward;
userData.currentStreak += 1;
if (userData.currentStreak > userData.bestStreak) {
userData.bestStreak = userData.currentStreak;
}
if (reward > userData.maxWin) {
userData.maxWin = reward;
}
} else {
resultMessage = "Íåóäà÷à! Ïîïðîáóé åùå ðàç.";
resultDisplay.textContent = resultMessage;
resultDisplay.className = "result-display lose-result";
userData.totalGames += 1;
userData.currentStreak = 0;
}
userData.lastSpin = Date.now();
userData.lastSpinResult = resultMessage;
console.log('📊 Updated user data after spin:', {
balance: userData.balance,
coins: userData.coins,
totalGames: userData.totalGames,
wins: userData.wins,
totalWinnings: userData.totalWinnings
});
// Ñîõðàíÿåì îáíîâëåííûå äàííûå
await saveUserData(userData);
// Îáíîâëÿåì èíòåðôåéñ
updateUserInfo();
await updateTopPlayers();
// Ñîçäàåì HTML ðåçóëüòàò
const messageHTML = createSlotResultHTML(results, isWin, reward, resultMessage);
const encoded = btoa(unescape(encodeURIComponent(messageHTML)));
// Îòïðàâëÿåì ðåçóëüòàò
sendToParent({
_slotMachine: true,
type: "slotResult",
payload: {
html: encoded,
userId: userData.userId,
nickname: userData.nickname,
result: resultMessage,
reward: reward,
balance: userData.balance,
coins: userData.coins,
timestamp: Date.now()
}
});
// Îáíîâëÿåì UI
updateSpinButton();
updateTimer();
}, Math.max(...durations));
}
// Ôóíêöèÿ ïîëó÷åíèÿ åæåäíåâíûõ æåòîíîâ
async function claimDailyCoinsHandler() {
if (!dailyCoinsBtn || !resultDisplay) return;
if (!canClaimDailyCoins()) {
resultDisplay.textContent = "Âû óæå ïîëó÷àëè æåòîíû ñåãîäíÿ!";
resultDisplay.className = "result-display lose-result";
return;
}
try {
dailyCoinsBtn.disabled = true;
resultDisplay.textContent = "Ïîëó÷àåì æåòîíû...";
resultDisplay.className = "result-display";
const result = await claimDailyCoins();
if (result.success) {
// Îáíîâëÿåì äàííûå ïîëüçîâàòåëÿ
userData.coins = result.coins;
userData.lastDailyCoins = result.lastDailyCoins;
resultDisplay.textContent = `🎉 Ïîëó÷åíî ${result.coinsAdded} æåòîí${result.coinsAdded > 1 ? 'à' : ''}! Âñåãî: ${result.coins} 🪙`;
resultDisplay.className = "result-display win-result";
// Ñîõðàíÿåì îáíîâëåííûå äàííûå
await saveUserData(userData);
// Îáíîâëÿåì èíòåðôåéñ
updateUserInfo();
updateSpinButton();
updateDailyCoinsUI();
}
} catch (error) {
console.error('❌ Error claiming daily coins:', error);
resultDisplay.textContent = error.message || "Îøèáêà ïîëó÷åíèÿ æåòîíîâ";
resultDisplay.className = "result-display lose-result";
updateDailyCoinsUI();
}
}
// Èíèöèàëèçàöèÿ
async function init() {
console.log('🎮 Initializing slot machine...');
try {
// Ñíà÷àëà òåñòèðóåì ñâÿçü ñ ping/pong
console.log('🔗 Testing connection with parent...');
const pingId = Date.now();
let pingReceived = false;
const pingHandler = (event) => {
const response = event.data;
if (response && response._slotMachine === true &&
response.type === "pong" && response.pingId === pingId) {
pingReceived = true;
console.log('✅ Ping received from parent');
window.removeEventListener("message", pingHandler);
}
};
window.addEventListener("message", pingHandler);
sendToParent({
_slotMachine: true,
type: "ping",
pingId: pingId
});
// Æäåì íåìíîãî îòâåòà
await new Promise(resolve => setTimeout(resolve, 1000));
if (!pingReceived) {
console.warn('⚠️ No ping response, but continuing anyway');
}
// Çàãðóæàåì äàííûå ïîëüçîâàòåëÿ
userData = await loadUserData();
console.log('👤 User data loaded:', userData);
console.log('💰 Current balance:', userData.balance);
console.log('🪙 Current coins:', userData.coins);
console.log('📅 Last daily coins:', userData.lastDailyCoins ? new Date(userData.lastDailyCoins).toLocaleString() : 'never');
// Îáíîâëÿåì èíòåðôåéñ
updateUserInfo();
await updateTopPlayers();
// Íàñòðàèâàåì îáðàáîò÷èêè
if (confirmBet) {
confirmBet.addEventListener("change", updateSpinButton);
updateSpinButton();
}
if (spinBtn) {
spinBtn.addEventListener("click", spinReels);
}
// Îáðàáîò÷èê äëÿ êíîïêè ïîëó÷åíèÿ æåòîíîâ
if (dailyCoinsBtn) {
dailyCoinsBtn.addEventListener("click", claimDailyCoinsHandler);
}
// Îáíîâëÿåì òàéìåðû
updateTimer();
updateDailyCoinsTimer();
const timerInterval = setInterval(updateTimer, 1000);
const dailyTimerInterval = setInterval(updateDailyCoinsTimer, 1000);
// Îáíîâëÿåì ñïèñîê èãðîêîâ ïåðèîäè÷åñêè
const topPlayersInterval = setInterval(async () => {
await updateTopPlayers();
}, 30000);
console.log("✅ Ñëîò-ìàøèíà èíèöèàëèçèðîâàíà!");
// Äîáàâëÿåì âîçìîæíîñòü âêëþ÷èòü/âûêëþ÷èòü äåáàã ÷åðåç êîíñîëü
window.toggleSlotDebug = function() {
debugMode = !debugMode;
console.log(`🎮 Debug mode ${debugMode ? 'enabled' : 'disabled'}`);
};
} catch (error) {
console.error("❌ Îøèáêà èíèöèàëèçàöèè:", error);
if (resultDisplay) {
resultDisplay.textContent = "Îøèáêà çàãðóçêè äàííûõ. Ïîïðîáóéòå îáíîâèòü ñòðàíèöó.";
resultDisplay.className = "result-display lose-result";
}
}
}
// Çàïóñê èíèöèàëèçàöèè
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})();
</script>
</body>
</html>[/html]
[hideprofile]


















































