import { GoogleGenAI } from "@google/genai"; // Not used, but kept for context if future AI features are added. // DOM Elements const gameArea = document.getElementById('game-area') as HTMLDivElement; const button = document.getElementById('futile-button') as HTMLButtonElement; const clickCountDisplay = document.getElementById('click-count') as HTMLSpanElement; const messageDisplay = document.getElementById('message-display') as HTMLDivElement; const gameTitle = document.getElementById('game-title') as HTMLHeadingElement; const gameInstructions = document.getElementById('game-instructions') as HTMLParagraphElement; const clicksLabel = document.getElementById('clicks-label') as HTMLSpanElement; const langEnButton = document.getElementById('lang-en') as HTMLButtonElement; const langZhButton = document.getElementById('lang-zh') as HTMLButtonElement; // Auth DOM Elements const authSection = document.getElementById('auth-section') as HTMLDivElement; const userStatusDisplay = document.getElementById('user-status') as HTMLSpanElement; const registerButton = document.getElementById('register-button') as HTMLButtonElement; const loginButton = document.getElementById('login-button') as HTMLButtonElement; const logoutButton = document.getElementById('logout-button') as HTMLButtonElement; // Modal DOM Elements const registerModal = document.getElementById('register-modal') as HTMLDivElement; const loginModal = document.getElementById('login-modal') as HTMLDivElement; const paymentModal = document.getElementById('payment-modal') as HTMLDivElement; const registerForm = document.getElementById('register-form') as HTMLFormElement; const loginForm = document.getElementById('login-form') as HTMLFormElement; // Premium Feature DOM Elements const premiumSection = document.getElementById('premium-section') as HTMLDivElement; const premiumTitle = premiumSection.querySelector('h3') as HTMLHeadingElement; const premiumBenefitsText = document.getElementById('premium-benefits-text') as HTMLParagraphElement; const goPremiumButton = document.getElementById('go-premium-button') as HTMLButtonElement; const zenModeStatusDisplay = document.getElementById('zen-mode-status') as HTMLParagraphElement; const confirmPaymentButton = document.getElementById('confirm-payment-button') as HTMLButtonElement; // Modal Titles & Notices const registerModalTitle = document.getElementById('register-modal-title') as HTMLHeadingElement; const regUsernameLabel = document.getElementById('reg-username-label') as HTMLLabelElement; const regEmailLabel = document.getElementById('reg-email-label') as HTMLLabelElement; const regPasswordLabel = document.getElementById('reg-password-label') as HTMLLabelElement; const registerSubmitButton = document.getElementById('register-submit-button') as HTMLButtonElement; const registerNotice = document.getElementById('register-notice') as HTMLParagraphElement; const loginModalTitle = document.getElementById('login-modal-title') as HTMLHeadingElement; const logUsernameLabel = document.getElementById('log-username-label') as HTMLLabelElement; const logPasswordLabel = document.getElementById('log-password-label') as HTMLLabelElement; const loginSubmitButton = document.getElementById('login-submit-button') as HTMLButtonElement; const loginNotice = document.getElementById('login-notice') as HTMLParagraphElement; const paymentModalTitle = document.getElementById('payment-modal-title') as HTMLHeadingElement; const paymentModalText = document.getElementById('payment-modal-text') as HTMLParagraphElement; const paymentNotice = document.getElementById('payment-notice') as HTMLParagraphElement; const premiumGlobalNotice = document.getElementById('premium-notice') as HTMLParagraphElement; // Leaderboard DOM Elements const leaderboardSection = document.getElementById('leaderboard-section') as HTMLDivElement; const leaderboardTitleEl = document.getElementById('leaderboard-title') as HTMLHeadingElement; const leaderboardTableBody = document.getElementById('leaderboard-table-body') as HTMLTableSectionElement; const leaderboardMessageEl = document.getElementById('leaderboard-message') as HTMLParagraphElement; const leaderboardRankHeader = document.getElementById('leaderboard-rank-header') as HTMLTableCellElement; const leaderboardUsernameHeader = document.getElementById('leaderboard-username-header') as HTMLTableCellElement; const leaderboardScoreHeader = document.getElementById('leaderboard-score-header') as HTMLTableCellElement; // Game State let clickCount = 0; let currentButtonWidth = 120; // Initial width in px let currentButtonHeight = 50; // Initial height in px const minButtonWidth = 30; const minButtonHeight = 15; let shrinkAmountWidth = 2; // px let shrinkAmountHeight = 1; // px const baseShrinkWidth = 2; const baseShrinkHeight = 1; const zenShrinkWidth = 1; // Slower shrink for Zen mode const zenShrinkHeight = 0.5; // Slower shrink for Zen mode // Language and Auth State type Language = 'en' | 'zh'; let currentLang: Language = (localStorage.getItem('gameLanguage') as Language) || 'en'; let isLoggedIn: boolean = false; let isPremiumUser: boolean = false; let currentUsername: string | null = null; // Leaderboard State interface LeaderboardEntry { username: string; score: number; } let leaderboardData: LeaderboardEntry[] = []; const MAX_LEADERBOARD_ENTRIES = 10; const LEADERBOARD_STORAGE_KEY = 'futileGameLeaderboard'; const translations = { en: { title: "The Futile Button Game", instructions: "Try to click the button. Good luck, you'll need it (not that it'll help).", clickMe: "Click Me!", clickMeSmall: "!", clicksLabelText: "Clicks", initialMessage: "Let's see how long you last.", resetMessage: "And we're back to square one! Enjoy!", tauntingMessages: [ "Oh, you clicked it. Impressive.", "Try again, I dare you.", "Is that all you've got?", "You're very persistent, I'll give you that.", "Almost... just kidding!", "This button is playing hard to get.", "Feeling frustrated yet?", "Maybe it'll be easier next time? (Spoiler: it won't)", "You can't win. You know that, right?", "Why are we still here? Just to suffer?", "The definition of insanity...", "This is my purpose. What's yours?", "I'm starting to enjoy this.", "Are you sure you don't have anything better to do?", "Okay, one more time. For science.", ], specialMessageDetails: [ { click: 10, message: "Wow, 10 clicks! You're a natural... at clicking." }, { click: 20, message: "20 clicks! The button is starting to feel threatened (not really)." }, { click: 30, message: "30! Are you trying to wear it down? It's digital!", action: () => actionChangeColor() }, { click: 42, message: "42 clicks. The answer to life, the universe, and everything... except winning this game." }, { click: 50, message: "50 CLICKS! The button is now tiny. What are you hoping for?", action: () => actionRotate() }, { click: 75, message: "75 clicks. You're a legend of futility!" }, { click: 100, message: "100 clicks. Okay, I'm genuinely impressed by your dedication to this pointless task. The button will now reset... for more fun!", action: () => { if (isLoggedIn && currentUsername) { updateUserScoreOnLeaderboard(currentUsername, 100); // Score is 100 } resetGameForFun(); } }, ], auth: { register: "Register", login: "Login", logout: "Logout", username: "Username", password: "Password", email: "Email", loggedInAs: "Logged in as: {username}", notLoggedIn: "You are not logged in.", registrationSuccess: "Registration successful! You can now log in.", loginSuccess: "Login successful!", loginFailed: "Login failed. Check username/password or register.", logoutSuccess: "Logged out successfully.", goPremium: "Unlock Zen Mode", premiumTitle: "Premium Features", premiumBenefits: "Unlock Zen Mode for a calmer, yet still futile, experience.", payNow: "Unlock Now (Simulated)", paymentSuccessful: "Zen Mode unlocked! Enjoy the enhanced futility.", alreadyPremium: "Zen Mode is active.", zenModeActive: "Zen Mode Active", zenTaunts: [ "The button moves, as does the river of time.", "Each click, a ripple in the pond of existence.", "Embrace the void, one click at a time.", "The journey is the destination, especially here.", "Patience, grasshopper. The button tests it.", "Observe the click, become the click.", "Futility, yet serenity. A paradox." ], zenResetMessage: "Balance achieved. The cycle of clicks continues...", premiumFeatureNotice: "Note: Registration and Premium features are simulated for demonstration purposes only. No real payment is processed.", registerModalTitle: "Register Account", loginModalTitle: "Login to Account", paymentModalTitle: "Unlock Zen Mode", paymentModalText: "Enjoy a slightly less frustrating, but equally unwinnable, experience with Zen Mode. Button shrinks slower, taunts are more philosophical.", confirmPaymentButton: "Unlock Now (Simulated Payment)", }, leaderboard: { title: "Leaderboard", rank: "Rank", username: "Username", score: "Score", yourRank: "Your Rank: #{rank}, Score: {score}", playToGetRanked: "Play a full game (100 clicks) to get on the leaderboard!", logInToSeeRank: "Log in or register to save your score and see your rank.", noScoresYet: "No scores yet. Be the first to make your mark!", noScoresYetBeFirst: "No scores yet. Be the first!", tryForTopTen: "Keep trying for the Top 10!" } }, zh: { title: "徒劳的按钮游戏", instructions: "试着点击按钮。祝你好运,你会需要的(虽然并没有什么用)。", clickMe: "点我!", clickMeSmall: "!", clicksLabelText: "点击次数", initialMessage: "看你能坚持多久。", resetMessage: "我们又回到了原点!祝你玩得开心!", tauntingMessages: [ "哦,你点击了它。真了不起。", "再试一次,我谅你也不敢。", "你就这点能耐吗?", "你非常执着,这点我承认。", "差一点……开玩笑的!", "这个按钮很难捉摸。", "感到沮丧了吗?", "也许下次会容易些?(剧透:并不会)", "你赢不了的。你知道的,对吧?", "我们为什么还在这里?只是为了受苦吗?", "精神错乱的定义……", "这是我的使命。你的是什么?", "我开始享受这个过程了。", "你确定没有更重要的事情要做吗?", "好吧,再来一次。为了科学。", ], specialMessageDetails: [ { click: 10, message: "哇,10 次点击!你真是个天生的……点击者。" }, { click: 20, message: "20 次点击!按钮开始感到威胁了(并没有)。" }, { click: 30, message: "30 次!你是想耗尽它吗?它是数字的!", action: () => actionChangeColor() }, { click: 42, message: "42 次点击。生命、宇宙以及一切的答案……除了赢得这个游戏。" }, { click: 50, message: "50 次点击!按钮现在变得很小了。你还期待什么?", action: () => actionRotate() }, { click: 75, message: "75 次点击。你是徒劳界的传奇!" }, { click: 100, message: "100 次点击。好吧,我真心佩服你对这项毫无意义的任务的执着。按钮现在将重置……为了更多的乐趣!", action: () => { if (isLoggedIn && currentUsername) { updateUserScoreOnLeaderboard(currentUsername, 100); } resetGameForFun(); } }, ], auth: { register: "注册", login: "登录", logout: "登出", username: "用户名", password: "密码", email: "邮箱", loggedInAs: "已登录用户:{username}", notLoggedIn: "您尚未登录。", registrationSuccess: "注册成功!您现在可以登录了。", loginSuccess: "登录成功!", loginFailed: "登录失败。请检查用户名/密码或注册。", logoutSuccess: "已成功登出。", goPremium: "解锁禅模式", premiumTitle: "高级功能", premiumBenefits: "解锁禅模式,体验更平静但依旧徒劳的游戏。", payNow: "立即解锁 (模拟)", paymentSuccessful: "禅模式已解锁!享受这增强的徒劳吧。", alreadyPremium: "禅模式已激活。", zenModeActive: "禅模式已激活", zenTaunts: [ "按钮移动,如同时光之河流。", "每一次点击,都是存在之池中的涟漪。", "一次一击,拥抱虚无。", "旅程即是终点,尤其在此处。", "耐心点,修行者。按钮考验着它。", "观察点击,成为点击。", "徒劳,却宁静。一种悖论。" ], zenResetMessage: "已达到平衡。点击的循环仍在继续...", premiumFeatureNotice: "注意:注册和高级功能均为模拟演示,不会处理真实付款。", registerModalTitle: "注册账户", loginModalTitle: "登录账户", paymentModalTitle: "解锁禅模式", paymentModalText: "体验一种不那么令人沮丧,但同样无法获胜的禅模式。按钮缩小更慢,提示语更富哲理。", confirmPaymentButton: "立即解锁 (模拟付款)", }, leaderboard: { title: "排行榜", rank: "排名", username: "用户名", score: "分数", yourRank: "您的排名:#{rank},分数:{score}", playToGetRanked: "完成一局游戏(100次点击)即可登上排行榜!", logInToSeeRank: "登录或注册以保存您的分数并查看排名。", noScoresYet: "排行榜上还没有分数。争当第一人!", noScoresYetBeFirst: "排行榜暂无记录,快来当第一名!", tryForTopTen: "继续努力进入前十名!" } } }; // --- Action Functions (defined once) --- const actionChangeColor = () => { button.style.backgroundColor = 'red'; setTimeout(() => { button.style.backgroundColor = isPremiumUser ? '#38A169' : '#667eea'; }, 1000); // Zen color or default }; const actionRotate = () => { button.style.transform = 'rotate(360deg)'; setTimeout(() => { button.style.transform = 'rotate(0deg)'; }, 500); }; // --- Leaderboard Functions --- function loadLeaderboard(): LeaderboardEntry[] { const storedLeaderboard = localStorage.getItem(LEADERBOARD_STORAGE_KEY); if (storedLeaderboard) { try { return JSON.parse(storedLeaderboard); } catch (e) { console.error("Error parsing leaderboard from localStorage", e); return []; } } return []; } function saveLeaderboard() { localStorage.setItem(LEADERBOARD_STORAGE_KEY, JSON.stringify(leaderboardData)); } function updateUserScoreOnLeaderboard(username: string, score: number) { const userIndex = leaderboardData.findIndex(entry => entry.username === username); if (userIndex > -1) { // User exists, update score only if new score is higher (though in this game, score is fixed at 100) // This logic is more for games with variable scores. Here, it just ensures they are on the board. if (score >= leaderboardData[userIndex].score) { // Use >= in case of re-playing leaderboardData[userIndex].score = score; } else { return; // No update needed if new score isn't better } } else { leaderboardData.push({ username, score }); } leaderboardData.sort((a, b) => b.score - a.score); // Sort descending by score // No slicing here, save the full sorted list. Slicing is for display only. saveLeaderboard(); renderLeaderboard(); } function renderLeaderboard() { const TL = translations[currentLang].leaderboard; leaderboardTitleEl.textContent = TL.title; leaderboardRankHeader.textContent = TL.rank; leaderboardUsernameHeader.textContent = TL.username; leaderboardScoreHeader.textContent = TL.score; leaderboardTableBody.innerHTML = ''; // Clear previous entries const leaderboardTable = leaderboardTableBody.parentElement as HTMLTableElement; const tableHeader = leaderboardTable.querySelector('thead'); if (leaderboardData.length === 0) { leaderboardMessageEl.textContent = isLoggedIn ? TL.noScoresYetBeFirst : TL.noScoresYet; if(tableHeader) tableHeader.style.display = 'none'; const row = leaderboardTableBody.insertRow(); const cell = row.insertCell(); cell.colSpan = 3; cell.textContent = isLoggedIn ? TL.noScoresYetBeFirst : TL.noScoresYet; cell.style.textAlign = 'center'; return; } if(tableHeader) tableHeader.style.display = ''; // Show header if there's data const topEntries = leaderboardData.slice(0, MAX_LEADERBOARD_ENTRIES); topEntries.forEach((entry, index) => { const row = leaderboardTableBody.insertRow(); row.insertCell().textContent = (index + 1).toString(); row.insertCell().textContent = entry.username; row.insertCell().textContent = entry.score.toString(); if (isLoggedIn && entry.username === currentUsername) { row.classList.add('user-highlight'); } }); if (isLoggedIn && currentUsername) { const userEntryIndex = leaderboardData.findIndex(e => e.username === currentUsername); if (userEntryIndex !== -1) { const rank = userEntryIndex + 1; const score = leaderboardData[userEntryIndex].score; let message = TL.yourRank.replace("{rank}", rank.toString()).replace("{score}", score.toString()); if (rank > MAX_LEADERBOARD_ENTRIES) { message += ` ${TL.tryForTopTen}`; } leaderboardMessageEl.textContent = message; } else { leaderboardMessageEl.textContent = TL.playToGetRanked; } } else { leaderboardMessageEl.textContent = TL.logInToSeeRank; } } function updateUIText() { const T = translations[currentLang]; const TA = T.auth; document.documentElement.lang = currentLang; gameTitle.textContent = T.title; gameInstructions.textContent = T.instructions; clicksLabel.textContent = T.clicksLabelText; if (currentButtonWidth < 60 || currentButtonHeight < 25) { button.textContent = (currentButtonWidth < 40) ? T.clickMeSmall : T.clickMe; } else { button.textContent = T.clickMe; } // Auth UI registerButton.textContent = TA.register; loginButton.textContent = TA.login; logoutButton.textContent = TA.logout; userStatusDisplay.textContent = isLoggedIn && currentUsername ? TA.loggedInAs.replace("{username}", currentUsername) : TA.notLoggedIn; // Premium UI premiumTitle.textContent = TA.premiumTitle; premiumBenefitsText.textContent = TA.premiumBenefits; goPremiumButton.textContent = TA.goPremium; zenModeStatusDisplay.textContent = TA.zenModeActive; premiumGlobalNotice.textContent = TA.premiumFeatureNotice; // Modal UI registerModalTitle.textContent = TA.registerModalTitle; regUsernameLabel.textContent = TA.username; regEmailLabel.textContent = TA.email; regPasswordLabel.textContent = TA.password; registerSubmitButton.textContent = TA.register; registerNotice.textContent = TA.premiumFeatureNotice; loginModalTitle.textContent = TA.loginModalTitle; logUsernameLabel.textContent = TA.username; logPasswordLabel.textContent = TA.password; loginSubmitButton.textContent = TA.login; loginNotice.textContent = TA.premiumFeatureNotice; paymentModalTitle.textContent = TA.paymentModalTitle; paymentModalText.textContent = TA.paymentModalText; (confirmPaymentButton as HTMLButtonElement).textContent = TA.confirmPaymentButton; paymentNotice.textContent = TA.premiumFeatureNotice; if (currentLang === 'en') { langEnButton.classList.add('active'); langZhButton.classList.remove('active'); } else { langZhButton.classList.add('active'); langEnButton.classList.remove('active'); } // Update current message if game hasn't started or was just reset if (clickCount === 0) { if (messageDisplay.dataset.justReset === 'true') { messageDisplay.textContent = isPremiumUser ? T.auth.zenResetMessage : T.resetMessage; } else { messageDisplay.textContent = T.initialMessage; } } renderLeaderboard(); // Ensure leaderboard text is also updated } function setLanguage(lang: Language) { currentLang = lang; localStorage.setItem('gameLanguage', lang); updateUIText(); // Re-evaluate current message if game is in progress if (clickCount > 0 && messageDisplay.dataset.justReset !== 'true') { displayMessage(false); // Call displayMessage without incrementing click count } else if (clickCount === 0 && messageDisplay.dataset.justReset === "true") { messageDisplay.textContent = isPremiumUser ? translations[currentLang].auth.zenResetMessage : translations[currentLang].resetMessage; } else if (clickCount === 0) { messageDisplay.textContent = translations[currentLang].initialMessage; } } function getRandomPosition(elementWidth: number, elementHeight: number): { top: number; left: number } { const gameAreaRect = gameArea.getBoundingClientRect(); const maxTop = gameAreaRect.height - elementHeight; const maxLeft = gameAreaRect.width - elementWidth; const top = Math.max(0, Math.floor(Math.random() * maxTop)); const left = Math.max(0, Math.floor(Math.random() * maxLeft)); return { top, left }; } function updateButtonState() { shrinkAmountWidth = isPremiumUser ? zenShrinkWidth : baseShrinkWidth; shrinkAmountHeight = isPremiumUser ? zenShrinkHeight : baseShrinkHeight; if (currentButtonWidth > minButtonWidth) currentButtonWidth -= shrinkAmountWidth; if (currentButtonHeight > minButtonHeight) currentButtonHeight -= shrinkAmountHeight; button.style.width = `${currentButtonWidth}px`; button.style.height = `${currentButtonHeight}px`; const T = translations[currentLang]; if (currentButtonWidth < 60 || currentButtonHeight < 25) { button.style.fontSize = '10px'; button.style.padding = '2px 4px'; button.textContent = (currentButtonWidth < 40) ? T.clickMeSmall : T.clickMe; } else { button.textContent = T.clickMe; button.style.fontSize = '16px'; button.style.padding = '10px 20px'; } const { top, left } = getRandomPosition(currentButtonWidth, currentButtonHeight); button.style.top = `${top}px`; button.style.left = `${left}px`; button.style.backgroundColor = isPremiumUser ? '#38A169' : '#667eea'; // Zen green or default blue } function displayMessage(incrementClicks: boolean = true) { if (incrementClicks) { clickCount++; } clickCountDisplay.textContent = clickCount.toString(); const T = translations[currentLang]; const currentTaunts = isPremiumUser ? T.auth.zenTaunts : T.tauntingMessages; let currentSpecialMessages = T.specialMessageDetails; if (isPremiumUser) { currentSpecialMessages = T.specialMessageDetails.map(sm => { if (sm.click === 100) { return { ...sm, message: T.auth.zenResetMessage, action: () => { if (isLoggedIn && currentUsername) { updateUserScoreOnLeaderboard(currentUsername, 100); } resetGameForFun(); } }; } return sm; }); } const specialMessageConfig = currentSpecialMessages.find(sm => sm.click === clickCount); if (clickCount === 0 && messageDisplay.dataset.justReset === 'true') { messageDisplay.textContent = isPremiumUser ? T.auth.zenResetMessage : T.resetMessage; delete messageDisplay.dataset.justReset; } else if (specialMessageConfig) { messageDisplay.textContent = specialMessageConfig.message; if (specialMessageConfig.action) { specialMessageConfig.action(); } } else { const randomIndex = Math.floor(Math.random() * currentTaunts.length); messageDisplay.textContent = currentTaunts[randomIndex]; } } function resetGameForFun() { clickCount = -1; // Will be incremented to 0 by displayMessage currentButtonWidth = 120; currentButtonHeight = 50; button.style.width = `${currentButtonWidth}px`; button.style.height = `${currentButtonHeight}px`; const T = translations[currentLang]; button.textContent = T.clickMe; button.style.fontSize = '16px'; button.style.padding = '10px 20px'; updateButtonState(); // initial position and color messageDisplay.dataset.justReset = 'true'; // Flag for next click's message } // Modal Management function showModal(modalId: string) { const modal = document.getElementById(modalId); if (modal) modal.style.display = 'block'; } function hideModal(modalId: string) { const modal = document.getElementById(modalId); if (modal) modal.style.display = 'none'; } // Auth Functions function updateAuthUI() { const T = translations[currentLang].auth; if (isLoggedIn && currentUsername) { userStatusDisplay.textContent = T.loggedInAs.replace("{username}", currentUsername); registerButton.style.display = 'none'; loginButton.style.display = 'none'; logoutButton.style.display = 'inline-block'; } else { userStatusDisplay.textContent = T.notLoggedIn; registerButton.style.display = 'inline-block'; loginButton.style.display = 'inline-block'; logoutButton.style.display = 'none'; } if (isPremiumUser) { goPremiumButton.textContent = T.alreadyPremium; goPremiumButton.disabled = true; zenModeStatusDisplay.style.display = 'block'; button.style.backgroundColor = '#38A169'; // Zen green shrinkAmountWidth = zenShrinkWidth; shrinkAmountHeight = zenShrinkHeight; } else { goPremiumButton.textContent = T.goPremium; goPremiumButton.disabled = false; zenModeStatusDisplay.style.display = 'none'; button.style.backgroundColor = '#667eea'; // Default blue shrinkAmountWidth = baseShrinkWidth; shrinkAmountHeight = baseShrinkHeight; } updateUIText(); // Refresh all text, which includes leaderboard renderLeaderboard(); // Also explicitly re-render leaderboard on auth change } function handleRegister(event: Event) { event.preventDefault(); const username = (document.getElementById('reg-username') as HTMLInputElement).value; const email = (document.getElementById('reg-email') as HTMLInputElement).value; const password = (document.getElementById('reg-password') as HTMLInputElement).value; if (!username || !password || !email) { alert("Please fill all fields for registration."); return; } localStorage.setItem(`mockUser_${username}`, JSON.stringify({ email, password })); alert(translations[currentLang].auth.registrationSuccess); hideModal('register-modal'); (registerForm as HTMLFormElement).reset(); } function handleLogin(event: Event) { event.preventDefault(); const username = (document.getElementById('log-username') as HTMLInputElement).value; const password = (document.getElementById('log-password') as HTMLInputElement).value; const storedUser = localStorage.getItem(`mockUser_${username}`); if (storedUser) { const userData = JSON.parse(storedUser); if (userData.password === password) { isLoggedIn = true; currentUsername = username; localStorage.setItem('loggedInUser', username); const premiumStatus = localStorage.getItem(`premiumUser_${username}`); isPremiumUser = premiumStatus === 'true'; if (isPremiumUser) localStorage.setItem('isPremium', 'true'); alert(translations[currentLang].auth.loginSuccess); hideModal('login-modal'); (loginForm as HTMLFormElement).reset(); updateAuthUI(); return; } } alert(translations[currentLang].auth.loginFailed); } function handleLogout() { isLoggedIn = false; isPremiumUser = false; currentUsername = null; localStorage.removeItem('loggedInUser'); localStorage.removeItem('isPremium'); alert(translations[currentLang].auth.logoutSuccess); updateAuthUI(); } function handleGoPremium() { if (!isLoggedIn) { alert("Please log in or register to unlock premium features."); showModal('login-modal'); return; } if (!isPremiumUser) { showModal('payment-modal'); } } function handleMockPayment() { if (currentUsername) { isPremiumUser = true; localStorage.setItem(`premiumUser_${currentUsername}`, 'true'); localStorage.setItem('isPremium', 'true'); alert(translations[currentLang].auth.paymentSuccessful); hideModal('payment-modal'); updateAuthUI(); } } function loadAuthState() { const loggedInUser = localStorage.getItem('loggedInUser'); const premiumSession = localStorage.getItem('isPremium'); if (loggedInUser) { isLoggedIn = true; currentUsername = loggedInUser; const userSpecificPremium = localStorage.getItem(`premiumUser_${currentUsername}`); isPremiumUser = userSpecificPremium === 'true'; if (isPremiumUser) localStorage.setItem('isPremium', 'true'); } if (premiumSession === 'true' && isLoggedIn) { isPremiumUser = true; } else { isPremiumUser = false; localStorage.removeItem('isPremium'); } } function initializeGame() { if (!gameArea || !button || !clickCountDisplay || !messageDisplay || !gameTitle || !gameInstructions || !clicksLabel || !langEnButton || !langZhButton || !authSection || !leaderboardSection) { console.error("Some game elements not found!"); return; } leaderboardData = loadLeaderboard(); loadAuthState(); setLanguage(currentLang); // This calls updateUIText (which calls renderLeaderboard) updateAuthUI(); // Explicit call to ensure auth UI is correct on load (calls updateUIText/renderLeaderboard) button.style.width = `${currentButtonWidth}px`; button.style.height = `${currentButtonHeight}px`; const { top, left } = getRandomPosition(currentButtonWidth, currentButtonHeight); button.style.top = `${top}px`; button.style.left = `${left}px`; button.addEventListener('click', () => { displayMessage(); if (clickCount !== 0 || (clickCount === 0 && messageDisplay.dataset.justReset !== 'true')) { updateButtonState(); } }); langEnButton.addEventListener('click', () => setLanguage('en')); langZhButton.addEventListener('click', () => setLanguage('zh')); registerButton.addEventListener('click', () => showModal('register-modal')); loginButton.addEventListener('click', () => showModal('login-modal')); logoutButton.addEventListener('click', handleLogout); goPremiumButton.addEventListener('click', handleGoPremium); confirmPaymentButton.addEventListener('click', handleMockPayment); document.querySelectorAll('.close-button').forEach(btn => { btn.addEventListener('click', (e) => { const modalId = (e.target as HTMLElement).dataset.modalId; if (modalId) hideModal(modalId); }); }); window.addEventListener('click', (event) => { if ((event.target as HTMLElement).classList.contains('modal')) { hideModal((event.target as HTMLElement).id); } }); registerForm.addEventListener('submit', handleRegister); loginForm.addEventListener('submit', handleLogin); gameArea.style.overflow = 'hidden'; messageDisplay.textContent = translations[currentLang].initialMessage; updateButtonState(); // Set initial button color based on potential Zen mode renderLeaderboard(); // Initial render of leaderboard } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initializeGame); } else { initializeGame(); }