require('dotenv').config(); global.crypto = require('crypto'); const { TelegramClient, Api } = require("telegram"); const { StringSession } = require("telegram/sessions"); const { NewMessage } = require("telegram/events"); const connectDB = require('./db/mongo'); const User = require('./models/User'); const { startApi } = require('./api'); const { processChatEarn } = require('./utils/chatEarn'); const { getName } = require('./utils/getName'); const { isGroupChat, miniAppButton, getBotUsername, getWebAppUrl } = require('./utils/miniAppButton'); const requiredEnv = ['API_ID', 'API_HASH', 'BOT_TOKEN', 'MONGO_URI']; const missing = requiredEnv.filter(k => !process.env[k]); if (missing.length > 0) console.warn(`⚠️ Missing env: ${missing.join(", ")}`); const economy = require('./handlers/economy'); const combat = require('./handlers/combat'); const games = require('./handlers/games'); const multiHack = require('./handlers/multiplayerHack'); const inlineGames = require('./handlers/inlineGames'); const inlineHandler = require('./handlers/inlineHandler'); const boardGames = require('./handlers/boardGames'); const boardHandler = require('./handlers/boardHandler'); const blackjack = require('./handlers/blackjack'); const strategy = require('./handlers/strategyGames'); const shopHandler = require('./handlers/shop'); const admin = require('./handlers/admin'); const carrom = require('./handlers/carrom'); const webCards = require('./handlers/webCards'); const omi = require('./handlers/omi'); const inlineMultiplayer = require('./handlers/inlineMultiplayer'); const apiId = parseInt(process.env.API_ID || 0); const apiHash = process.env.API_HASH || ""; const botToken = process.env.BOT_TOKEN || ""; const stringSession = new StringSession(""); const MP_FALLBACK = "⚠️ This command only works in groups! Add me to a group to play multiplayer games."; (async () => { await connectDB(); startApi(); const client = new TelegramClient(stringSession, apiId, apiHash, { connectionRetries: 5 }); await client.start({ botAuthToken: botToken }); console.log("Bot is running..."); global._tgClient = client; client.setParseMode('html'); const isAlive = async (event) => { const userId = event.message.senderId.toString(); const user = await User.findOne({ userId }); if (user && user.isDead) { if (Date.now() - (user.lastDeath || 0) > 4 * 60 * 60 * 1000) { user.isDead = false; user.health = 100; await user.save(); return true; } await event.message.respond({ message: "💀 You are dead! Use /revive or wait 4 hours." }); return false; } return true; }; const isBlacklisted = async (userId) => { const user = await User.findOne({ userId }); return user && user.blacklisted; }; const requireGroup = (event) => { if (!isGroupChat(event.chatId)) { event.message.respond({ message: MP_FALLBACK }); return false; } return true; }; /** * Strip @botusername from command text. * "/chess@Alexagamebot 500" → "/chess 500" * "/daily@Alexagamebot" → "/daily" */ function stripBotMention(text) { return text.replace(/@\w+/i, ''); } /** * Check if text matches a command (handles @botusername suffix). * cmd("/daily", text) matches "/daily" and "/daily@Alexagamebot" */ function cmd(command, text) { return text === command || text.startsWith(command + '@') || text.startsWith(command + ' '); } /** * Check if text starts with a command (handles @botusername). * cmdStart("/chess", text) matches "/chess 500" and "/chess@Bot 500" */ function cmdStart(command, text) { return text.startsWith(command + ' ') || text.startsWith(command + '@') || text === command; } client.addEventHandler(async (event) => { const rawText = event.message.message || ''; const userId = event.message.senderId?.toString(); if (!userId) return; // Auto-earn from chatting (non-commands, groups only) if (rawText && !rawText.startsWith('/')) { if (isGroupChat(event.chatId)) await processChatEarn(userId); return; } if (!rawText) return; // Strip @botusername from the command for matching const text = stripBotMention(rawText); // Blacklist check if (text.startsWith('/') && await isBlacklisted(userId)) return; // ── Admin ── if (cmdStart("/add", text) && !cmdStart("/addblacklist", text)) await admin.addMoney(client, event); if (cmdStart("/addblacklist", text)) await admin.addBlacklist(client, event); if (cmdStart("/unblacklist", text)) await admin.unBlacklist(client, event); if (cmd("/blacklist", text)) await admin.showBlacklist(client, event); // ── /start — handle startapp params for mini app deep links ── if (text === "/start" || text.startsWith("/start ")) { const parts = text.split(" "); const startParam = parts[1] || ''; // Handle startapp deep links (carrom, daily, mission, etc.) if (startParam.startsWith('omi_')) { const webUrl = getWebAppUrl() + '/omi.html?tgWebAppStartParam=' + startParam; await client.sendMessage(event.chatId, { message: "🃏 Omi\n\nClick below to open!", buttons: new Api.ReplyInlineMarkup({ rows: [new Api.KeyboardButtonRow({ buttons: [ new Api.KeyboardButtonWebView({ text: "🃏 Open Omi", url: webUrl }) ]})] }) }); return; } if (startParam.startsWith('wcards_')) { const webUrl = getWebAppUrl() + '/cards.html?tgWebAppStartParam=' + startParam; await client.sendMessage(event.chatId, { message: "🃏 Card Game\n\nClick below to open!", buttons: new Api.ReplyInlineMarkup({ rows: [new Api.KeyboardButtonRow({ buttons: [ new Api.KeyboardButtonWebView({ text: "🃏 Open Cards", url: webUrl }) ]})] }) }); return; } if (startParam.startsWith('carrom_')) { // Send mini app button to open carrom game const webUrl = getWebAppUrl() + '/carrom?tgWebAppStartParam=' + startParam; await client.sendMessage(event.chatId, { message: "🎯 Carrom Pool\n\nClick below to open the game!", buttons: new Api.ReplyInlineMarkup({ rows: [new Api.KeyboardButtonRow({ buttons: [ new Api.KeyboardButtonWebView({ text: "🎮 Open Carrom", url: webUrl }) ]})] }) }); return; } if (startParam === 'daily') { await economy.daily(client, event); return; } if (startParam === 'mission') { await economy.missions(client, event); return; } // Default /start — show help await event.message.respond({ message: "🎮 Alexagame Bot\n\n" + "💰 /daily — Claim $3000 daily reward\n" + "💰 /wallet — Balance & stats\n" + "🛒 /shop — Browse items\n" + "🛍️ /buy <id> — Buy item\n" + "🎁 /gift <id> — Gift item (reply)\n" + "📦 /collection — View collection\n\n" + "⚔️ Combat (groups only)\n" + "/kill (reply) — Kill for cash\n" + "/rob <amount> (reply) — Rob user\n" + "/revive — Revive for $1000\n\n" + "🎮 Multiplayer (groups only)\n" + "♔ /chess <bet> — Chess\n" + "⚪ /checkers <bet> — Checkers\n" + "❌ /xox <bet> — Tic-Tac-Toe 8×8\n" + "🔴 /c4 <bet> — Connect 4 8×8\n" + "🎲 /dice <bet> — Dice duel\n" + "🎯 /carrom <bet> — Carrom Pool\n" + "🔓 /hack <bet> <len> — PIN hack\n" + "🃏 /cards <bet> — Card Game\n" + "🃏 /omi <bet> — Omi (trick-taking)\n\n" + "🎰 Solo Casino\n" + "/bj <bet> — Blackjack\n" + "/slots — Slots | /mines — Mines\n" + "/coin — Coin flip | /hl — High/Low\n" + "/roulette — Russian roulette\n\n" + "🏳️ /surrender — Forfeit game\n" + "💬 Chat in groups to earn up to $1000/day!" }); return; } // ── Wallet (works everywhere) ── if (cmd("/wallet", text)) { let targetId = userId; if (event.message.replyTo) { try { const replyMsg = await client.getMessages(event.chatId, { ids: [event.message.replyTo.replyToMsgId] }); if (replyMsg?.[0]?.senderId) targetId = replyMsg[0].senderId.toString(); } catch (e) {} } let user = await User.findOne({ userId: targetId }) || await User.create({ userId: targetId }); const name = await getName(client, targetId); await event.message.respond({ message: `👤 ${name}${targetId === userId ? '' : "'s wallet"}\n` + `🎖️ Lv.${user.level} | XP: ${user.xp}\n` + `💰 Wallet: $${user.wallet}\n` + `💳 Bank: $${user.bank}\n` + `❤️ HP: ${user.health}%\n` + `💀 Kills: ${user.kills||0} | 💸 Robs: ${user.robs||0}\n` + `📦 Items: ${user.inventory?.length || 0}` }); } // ── Economy (works everywhere) ── if (cmd("/daily", text)) await economy.daily(client, event); if (cmd("/missions", text)) await economy.missions(client, event); if (cmdStart("/dp", text)) await economy.deposit(client, event); if (cmdStart("/wd", text)) await economy.withdraw(client, event); // ── Shop (works everywhere) ── if (cmd("/shop", text)) await shopHandler.shop(client, event); if (cmdStart("/buy", text)) await shopHandler.buy(client, event); if (cmdStart("/gift", text) && event.message.replyTo) await shopHandler.gift(client, event); if (cmd("/collection", text) || (cmdStart("/collection", text) && event.message.replyTo)) await shopHandler.inventory(client, event); // ── Solo Casino (works everywhere) ── if (cmdStart("/bj", text)) { if (await isAlive(event)) await blackjack.startBJ(client, event); } if (cmd("/slots", text)) await inlineGames.startSlots(client, event); if (cmd("/mines", text)) await inlineGames.startMines(client, event); if (cmd("/coin", text)) await inlineGames.startFlip(client, event); if (cmd("/roulette", text)) await inlineGames.startRoulette(client, event); if (cmd("/hl", text)) await inlineGames.startHL(client, event); // ── Combat (groups only) ── if (cmdStart("/kill", text)) { if (requireGroup(event) && await isAlive(event)) await combat.kill(client, event); } if (cmdStart("/rob", text)) { if (requireGroup(event) && await isAlive(event)) await combat.rob(client, event); } if (cmd("/revive", text)) await combat.revive(client, event); // ── Multiplayer games (groups only) ── if (cmdStart("/chess", text)) { if (requireGroup(event) && await isAlive(event)) await strategy.startChess(client, event); } if (cmdStart("/checkers", text)) { if (requireGroup(event) && await isAlive(event)) await strategy.startCheckers(client, event); } if (cmdStart("/xox", text)) { if (requireGroup(event) && await isAlive(event)) await boardGames.startXOX(client, event); } if (cmdStart("/c4", text)) { if (requireGroup(event) && await isAlive(event)) await boardGames.startC4(client, event); } if (cmdStart("/dice", text)) { if (requireGroup(event) && await isAlive(event)) await games.startDice(client, event); } if (cmdStart("/cards", text) || cmdStart("/wcards", text)) { if (requireGroup(event) && await isAlive(event)) await webCards.startWebCards(client, event); } if (cmdStart("/omi", text)) { if (requireGroup(event) && await isAlive(event)) await omi.startOmi(client, event); } if (cmdStart("/carrom", text)) { if (requireGroup(event) && await isAlive(event)) await carrom.startCarrom(client, event); } if (cmdStart("/hack", text)) { if (requireGroup(event) && await isAlive(event)) await multiHack.initHack(client, event); } if (cmd("/join", text)) { if (isGroupChat(event.chatId)) { await multiHack.joinHack(client, event); } } if (cmdStart("/guess", text)) await multiHack.processGuess(client, event); if (cmd("/surrender", text)) await strategy.surrender(client, event); }, new NewMessage({})); // Inline queries + callback queries client.addEventHandler(async (update) => { if (update instanceof Api.UpdateBotInlineQuery) { try { await inlineMultiplayer.handleInlineQuery(client, update); } catch (e) { console.error('[INLINE QUERY]:', e.message); } return; } if (update instanceof Api.UpdateBotCallbackQuery || update instanceof Api.UpdateInlineBotCallbackQuery) { const cbUserId = update.userId.toString(); if (await isBlacklisted(cbUserId)) return; let handled = false; const cbData = update.data.toString(); if (cbData.startsWith("omjn|")) { try { await omi.handleOmiCallback(client, update); } catch (e) { console.error('[CB] omi:', e.message); } handled = true; } if (cbData.startsWith("wcjn|")) { try { await webCards.handleWebCardsCallback(client, update); } catch (e) { console.error('[CB] wcards:', e.message); } handled = true; } if (cbData.startsWith("crmjn|") || cbData.startsWith("crmst|")) { try { await carrom.handleCarromCallback(client, update); } catch (e) { console.error('[CB] carrom:', e.message); } handled = true; } if (cbData.startsWith("cs|") || cbData.startsWith("ck|") || cbData.startsWith("csjn|") || cbData.startsWith("ckjn|") || cbData.startsWith("cssr|") || cbData.startsWith("cksr|")) { try { await strategy.handleStrategyCallback(client, update); } catch (e) { console.error('[CB] strategy:', e.message); } handled = true; } if (!handled) { try { await games.handleCallback(client, update); } catch (e) { console.error('[CB] games:', e.message); } try { await games.handleDiceCallback(client, update); } catch (e) { console.error('[CB] dice:', e.message); } try { await inlineHandler.handleInlineCallback(client, update); } catch (e) { console.error('[CB] inline:', e.message); } try { await boardHandler.handleBoardCallback(client, update); } catch (e) { console.error('[CB] board:', e.message); } try { await blackjack.handleBJCallback(client, update); } catch (e) { console.error('[CB] bj:', e.message); } try { await client.invoke(new Api.messages.SetBotCallbackAnswer({ queryId: update.queryId, cacheTime: 1 })); } catch (e) {} } } }); })();