// ==UserScript== // @name Gartic Anonimbiri Bot Panel // @name:tr Gartic Anonimbiri Bot Paneli // @namespace http://tampermonkey.net/ // @version 2025-07-02 // @description Advanced bot control panel for gartic.io with a gorgeous dark theme, smart inputs, AFK prevention, and i18n support. // @description:tr Harika koyu tema, akıllı girdiler, AFK önleme ve çoklu dil desteği ile gartic.io için gelişmiş bot kontrol paneli. // @author anonimbiri // @license MIT // @match https://gartic.io/anonimbiri // @icon https://cdn.jsdelivr.net/gh/GameSketchers/Kawaii-Helper@refs/heads/main/Assets/kawaii-logo.png // @grant GM_cookie // @downloadURL https://update.greasyfork.icu/scripts/533419/Gartic%20Anonimbiri%20Bot%20Panel.user.js // @updateURL https://update.greasyfork.icu/scripts/533419/Gartic%20Anonimbiri%20Bot%20Panel.meta.js // ==/UserScript== (function() { 'use strict'; // Custom console logging const log = (msg, error = false) => { console.log(`%c[anonimbiri] ${msg}`, `color:${error ? '#ff5555' : '#00ff88'};font-weight:bold;font-family:monospace;background:#1a1a2e;padding:2px 4px;border-radius:3px`); }; // Initial cookie deletion for the main panel page GM_cookie.delete({ name: 'garticio' }, (error) => log(error ? '✖ garticio cookie error' : '✔ garticio cookie deleted')); GM_cookie.delete({ name: 'cf_clearance' }, (error) => log(error ? '✖ cf_clearance cookie error' : '✔ cf_clearance cookie deleted')); // Replace page with the new modern dark theme document.documentElement.innerHTML = `
Kawaii Mascot
🇹🇷 Türkçe
🇺🇸 English
🇯🇵 日本語

by anonimbiri

`; // --- I18N (Internationalization) --- const translations = { en: { playersTitle: "Players in Room", roomCodeLabel: "Room Code:", themeLabel: "Theme:", notConnected: "Not connected", noTheme: "-", noPlayers: "No player information yet...", botControlTitle: "Gartic Bot Control", botCountLabel: "Bot Count:", roomCodeInputLabel: "Room Code:", roomCodePlaceholder: "e.g. 32v1sA", startBotsBtn: "Start Bots", creatingBotsBtn: "Creating...", deleteBotsBtn: "Delete All Bots", statusConsoleLabel: "Status Console:", spamControlTitle: "Bot Spam Control", spamTextLabel: "Spam Text:", spamTextPlaceholder: "Message to send", spamIntervalLabel: "Spam Interval (ms):", spamChannelLabel: "Spam Channel:", spamChannelAnswers: "Answers (42[13])", spamChannelChat: "Chat (42[11])", startSpamBtn: "Start Spam", stopSpamBtn: "Stop Spam", reportDrawingBtn: "Report Drawing", kickBtn: "Kick", points: "Points", wins: "Wins", initLog: "Bot panel active! Enter details and click the button to start.", startingBotsLog: (c, r) => `${c} bots are starting... Room: ${r}`, websocketUrlLog: "WebSocket URL created.", botCreatingLog: i => `Creating bot ${i}...`, playBtnLog: i => `Bot ${i}: Clicked play button`, playBtnErrLog: i => `Bot ${i}: Play button not found`, credsLog: i => `Bot ${i}: Credentials received`, jsonErrLog: i => `Bot ${i}: JSON parse error`, iframeErrLog: i => `Bot ${i}: Iframe loading error`, iframeRemovedLog: "Temporary iframe removed.", wsConnectingLog: i => `Bot ${i}: Connecting to game server...`, wsOpenLog: i => `Bot ${i}: Connection opened`, wsJoinedLog: (i, n) => `Bot ${i}: Joined as "${n}"`, wsReadyLog: i => `Bot ${i}: Active and ready`, wsDataErrLog: i => `Bot ${i}: Game data parse error`, wsRoomFullLog: i => `Bot ${i}: Error 3 - Room is full`, wsInGameLog: (i, c) => `Bot ${i}: Error 4 - Already in game. Use viewer: https://gartic.io/${c}/viewer`, wsLeaveConfirmLog: i => `Bot ${i}: Leave confirmed`, wsErrorLog: i => `Bot ${i}: Connection error`, wsCloseLog: i => `Bot ${i}: Connection closed`, allBotsSuccessLog: c => `All ${c} bots started successfully! ✨`, noBotsToKick: "No active connection to perform kick!", kickSentLog: (p, s) => `Kick request sent for player: ${p} (Socket ${s})`, kickFailLog: "Kick failed: Missing player ID", noBotsToSpam: "No active bots for spam!", spamTextRequired: "Please enter a spam text!", spamStartedLog: (t, c) => `Spam started: "${t}" (${c})`, spamStoppedLog: "Spam stopped.", noBotsToDelete: "No active bots to delete!", leaveCmdLog: (i, p) => `Bot ${i} leave command sent: ${p}`, urlExtractedLog: c => `Room code extracted from URL: ${c}`, newPlayerLog: n => `New player: ${n}`, playerLeftLog: i => `Player left: ID ${i}` }, tr: { playersTitle: "Odadaki Oyuncular", roomCodeLabel: "Oda Kodu:", themeLabel: "Tema:", notConnected: "Henüz bağlanılmadı", noTheme: "-", noPlayers: "Henüz oyuncu bilgisi yok...", botControlTitle: "Gartic Bot Kontrol", botCountLabel: "Bot Sayısı:", roomCodeInputLabel: "Oda Kodu:", roomCodePlaceholder: "Örn. 32v1sA", startBotsBtn: "Botları Başlat", creatingBotsBtn: "Oluşturuluyor...", deleteBotsBtn: "Tüm Botları Sil", statusConsoleLabel: "Durum Konsolu:", spamControlTitle: "Bot Spam Kontrol", spamTextLabel: "Spam Metni:", spamTextPlaceholder: "Gönderilecek mesaj", spamIntervalLabel: "Spam Aralığı (ms):", spamChannelLabel: "Spam Kanalı:", spamChannelAnswers: "Cevaplar (42[13])", spamChannelChat: "Sohbet (42[11])", startSpamBtn: "Spam Başlat", stopSpamBtn: "Spam Durdur", reportDrawingBtn: "Çizimi Raporla", kickBtn: "At", points: "Puan", wins: "Galibiyet", initLog: "Bot paneli aktif! Bilgileri girip botları başlatmak için butona tıklayın.", startingBotsLog: (c, r) => `${c} bot başlatılıyor... Oda: ${r}`, websocketUrlLog: "WebSocket URL oluşturuldu.", botCreatingLog: i => `Bot ${i} oluşturuluyor...`, playBtnLog: i => `Bot ${i}: Oyun butonuna tıklandı`, playBtnErrLog: i => `Bot ${i}: Oyun butonu bulunamadı`, credsLog: i => `Bot ${i}: Kimlik bilgileri alındı`, jsonErrLog: i => `Bot ${i}: JSON ayrıştırma hatası`, iframeErrLog: i => `Bot ${i}: Iframe yükleme hatası`, iframeRemovedLog: "Geçici iframe kaldırıldı.", wsConnectingLog: i => `Bot ${i}: Oyun sunucusuna bağlanıyor...`, wsOpenLog: i => `Bot ${i}: Bağlantı açıldı`, wsJoinedLog: (i, n) => `Bot ${i}: "${n}" olarak katıldı`, wsReadyLog: i => `Bot ${i}: Aktif ve hazır`, wsDataErrLog: i => `Bot ${i}: Oyun verisi ayrıştırma hatası`, wsRoomFullLog: i => `Bot ${i}: Hata 3 - Oda dolu`, wsInGameLog: (i, c) => `Bot ${i}: Hata 4 - Zaten oyundasınız. İzleyici moduna geçin: https://gartic.io/${c}/viewer`, wsLeaveConfirmLog: i => `Bot ${i}: Ayrılma onaylandı`, wsErrorLog: i => `Bot ${i}: Bağlantı hatası`, wsCloseLog: i => `Bot ${i}: Bağlantı kapandı`, allBotsSuccessLog: c => `Tüm ${c} bot başarıyla başlatıldı! ✨`, noBotsToKick: "Atma işlemi için aktif bağlantı bulunamadı!", kickSentLog: (p, s) => `Oyuncu atma işlemi gönderildi: ${p} (Soket ${s})`, kickFailLog: "Atma başarısız: Oyuncu ID eksik", noBotsToSpam: "Spam için aktif bot bulunamadı!", spamTextRequired: "Lütfen bir spam metni girin!", spamStartedLog: (t, c) => `Spam başlatıldı: "${t}" (${c})`, spamStoppedLog: "Spam durduruldu.", noBotsToDelete: "Silinecek aktif bot bulunamadı!", leaveCmdLog: (i, p) => `Bot ${i} ayrılma komutu gönderildi: ${p}`, urlExtractedLog: c => `URL'den oda kodu çıkarıldı: ${c}`, newPlayerLog: n => `Yeni oyuncu: ${n}`, playerLeftLog: i => `Oyuncu ayrıldı: ID ${i}` }, ja: { playersTitle: "ルーム内のプレイヤー", roomCodeLabel: "ルームコード:", themeLabel: "テーマ:", notConnected: "未接続", noTheme: "-", noPlayers: "プレイヤー情報がまだありません...", botControlTitle: "Garticボットコントロール", botCountLabel: "ボット数:", roomCodeInputLabel: "ルームコード:", roomCodePlaceholder: "例: 32v1sA", startBotsBtn: "ボットを開始", creatingBotsBtn: "作成中...", deleteBotsBtn: "全ボットを削除", statusConsoleLabel: "ステータスコンソール:", spamControlTitle: "ボットスパム制御", spamTextLabel: "スパムテキスト:", spamTextPlaceholder: "送信するメッセージ", spamIntervalLabel: "スパム間隔 (ms):", spamChannelLabel: "スパムチャンネル:", spamChannelAnswers: "回答 (42[13])", spamChannelChat: "チャット (42[11])", startSpamBtn: "スパムを開始", stopSpamBtn: "スパムを停止", reportDrawingBtn: "描画を報告", kickBtn: "追放", points: "ポイント", wins: "勝利数", initLog: "ボットパネルがアクティブです!詳細を入力してボタンをクリックして開始します。", startingBotsLog: (c, r) => `${c}体のボットを開始しています... ルーム: ${r}`, websocketUrlLog: "WebSocket URLが作成されました。", botCreatingLog: i => `ボット${i}を作成中...`, playBtnLog: i => `ボット${i}: 再生ボタンをクリック`, playBtnErrLog: i => `ボット${i}: 再生ボタンが見つかりません`, credsLog: i => `ボット${i}: 資格情報を受信`, jsonErrLog: i => `ボット${i}: JSON解析エラー`, iframeErrLog: i => `ボット${i}: Iframe読み込みエラー`, iframeRemovedLog: "一時的なiframeが削除されました。", wsConnectingLog: i => `ボット${i}: ゲームサーバーに接続中...`, wsOpenLog: i => `ボット${i}: 接続が開きました`, wsJoinedLog: (i, n) => `ボット${i}: "${n}"として参加`, wsReadyLog: i => `ボット${i}: アクティブで準備完了`, wsDataErrLog: i => `ボット${i}: ゲームデータ解析エラー`, wsRoomFullLog: i => `ボット${i}: エラー3 - ルームが満員です`, wsInGameLog: (i, c) => `ボット${i}: エラー4 - 既にゲームに参加中。視聴者モードを使用: https://gartic.io/${c}/viewer`, wsLeaveConfirmLog: i => `ボット${i}: 退出を確認`, wsErrorLog: i => `ボット${i}: 接続エラー`, wsCloseLog: i => `ボット${i}: 接続が閉じました`, allBotsSuccessLog: c => `全${c}体のボットが正常に開始されました!✨`, noBotsToKick: "追放アクションを実行する接続がありません!", kickSentLog: (p, s) => `プレイヤー追放リクエスト送信: ${p} (ソケット ${s})`, kickFailLog: "追放失敗: プレイヤーIDがありません", noBotsToSpam: "スパム用のアクティブなボットがいません!", spamTextRequired: "スパムテキストを入力してください!", spamStartedLog: (t, c) => `スパム開始: "${t}" (${c})`, spamStoppedLog: "スパムを停止しました。", noBotsToDelete: "削除するアクティブなボットがいません!", leaveCmdLog: (i, p) => `ボット${i}退出コマンド送信: ${p}`, urlExtractedLog: c => `URLからルームコード抽出: ${c}`, newPlayerLog: n => `新しいプレイヤー: ${n}`, playerLeftLog: i => `プレイヤーが退出: ID ${i}` } }; let currentLang = 'tr'; const applyTranslations = () => { const t = translations[currentLang]; document.querySelectorAll('[data-translate]').forEach(el => { if (t[el.dataset.translate]) el.textContent = t[el.dataset.translate]; }); document.querySelectorAll('[data-translate-placeholder]').forEach(el => { if (t[el.dataset.translatePlaceholder]) el.placeholder = t[el.dataset.translatePlaceholder]; }); document.getElementById('roomCodeDisplay').textContent = t.notConnected; document.getElementById('roomTheme').textContent = t.noTheme; document.getElementById('playerList').innerHTML = `
${t.noPlayers}
`; updateButtonState(); stopSpam(); updatePlayerListUI(); }; // --- UI INTERACTION --- const initCustomUI = () => { document.querySelectorAll('.number-btn').forEach(btn => { btn.addEventListener('click', () => { const targetInput = document.getElementById(btn.dataset.target); const step = btn.dataset.step === 'up' ? 1 : -1; const min = parseInt(targetInput.min); const max = parseInt(targetInput.max); let value = (parseInt(targetInput.value) || 0) + step; if (!isNaN(min) && value < min) value = min; if (!isNaN(max) && value > max) value = max; targetInput.value = value; }); }); document.querySelectorAll('.custom-select').forEach(container => { const display = container.querySelector('.select-display'); const optionsContainer = container.querySelector('.select-options'); const textEl = container.querySelector('.select-text'); display.addEventListener('click', (e) => { e.stopPropagation(); const isActive = optionsContainer.classList.toggle('active'); display.classList.toggle('active', isActive); }); optionsContainer.querySelectorAll('.select-option').forEach(option => { option.addEventListener('click', () => { textEl.textContent = translations[currentLang][option.dataset.translate] || option.textContent; container.dataset.value = option.dataset.value; container.querySelectorAll('.select-option').forEach(opt => opt.classList.remove('selected')); option.classList.add('selected'); if (container.id === 'languageSelectContainer') setLanguage(option.dataset.value); }); }); const initialSelected = optionsContainer.querySelector('.select-option.selected') || optionsContainer.querySelector('.select-option'); if (initialSelected) { textEl.textContent = translations[currentLang][initialSelected.dataset.translate] || initialSelected.textContent; container.dataset.value = initialSelected.dataset.value; } }); document.addEventListener('click', () => { document.querySelectorAll('.custom-select').forEach(container => { container.querySelector('.select-options').classList.remove('active'); container.querySelector('.select-display').classList.remove('active'); }); }); }; const setLanguage = (lang) => { currentLang = translations[lang] ? lang : 'tr'; const langContainer = document.getElementById('languageSelectContainer'); const selectedLangOption = langContainer.querySelector(`.select-option[data-value="${currentLang}"]`); if(selectedLangOption) { langContainer.querySelector('.select-text').textContent = selectedLangOption.textContent; langContainer.querySelectorAll('.select-option').forEach(opt => opt.classList.remove('selected')); selectedLangOption.classList.add('selected'); } const spamContainer = document.getElementById('spamChannelSelectContainer'); const selectedSpamOption = spamContainer.querySelector('.select-option.selected'); if(selectedSpamOption) { spamContainer.querySelector('.select-text').textContent = translations[currentLang][selectedSpamOption.dataset.translate]; } applyTranslations(); }; // --- CORE BOT LOGIC --- const statusLog = (msg, type = '') => { const logEl = document.getElementById('statusLog'); if (!logEl) return; const newLine = document.createElement('div'); newLine.className = `console-line ${type}`; newLine.textContent = `→ ${msg}`; logEl.appendChild(newLine); logEl.scrollTop = logEl.scrollHeight; }; const spamLog = (msg) => { statusLog(msg, 'spam'); }; let token, sala, botCount, roomCode, websocketUrl = null; let playerList = [], socketList = [], botQueue = [], botChoices = new Map(); let botsCreated = 0, isCreatingBot = false, currentIframe = null, spamInterval = null, isSpamming = false; let afkInterval = null; const startBotsButton = document.getElementById('startBots'); const invisibleChars = ['\u200B', '\u200C', '\u200D', '\u2061', '\u2062', '\u2063']; function insertInvisibleChar(text) { const r = invisibleChars[Math.floor(Math.random()*invisibleChars.length)], p = Math.floor(Math.random()*(text.length+1)); return text.slice(0,p)+r+text.slice(p); } function updateButtonState(isLoading = false) { const t = translations[currentLang]; startBotsButton.textContent = isLoading ? t.creatingBotsBtn : (socketList.length > 0 ? t.deleteBotsBtn : t.startBotsBtn); startBotsButton.disabled = isLoading; startBotsButton.classList.toggle('btn-danger', !isLoading && socketList.length > 0); } function startSpam() { const t = translations[currentLang]; if (socketList.length === 0) { spamLog(t.noBotsToSpam); return; } const spamTextBase = document.getElementById('spamText').value.trim(); const spamChannel = document.getElementById('spamChannelSelectContainer').dataset.value; const spamIntervalValue = parseInt(document.getElementById('spamInterval').value) || 1000; if (!spamTextBase) { spamLog(t.spamTextRequired); return; } isSpamming = true; const startSpamButton = document.getElementById('startSpam'); startSpamButton.textContent = t.stopSpamBtn; startSpamButton.classList.add('btn-danger'); const channelName = document.querySelector(`#spamChannelSelectContainer .select-option.selected`).textContent; spamLog(t.spamStartedLog(spamTextBase, channelName)); const commandCode = spamChannel === "answers" ? "13" : "11"; clearInterval(spamInterval); spamInterval = setInterval(() => { socketList.forEach((socket, index) => { if (socket.readyState === WebSocket.OPEN && socket.playerId) { socket.send(`42[${commandCode},${socket.playerId},"${insertInvisibleChar(spamTextBase)}"]`); log(`Spam message sent from socket ${index} (${commandCode})`); } }); }, spamIntervalValue); } function stopSpam() { const t = translations[currentLang]; const startSpamButton = document.getElementById('startSpam'); startSpamButton.textContent = t.startSpamBtn; startSpamButton.classList.remove('btn-danger'); if (isSpamming) { clearInterval(spamInterval); isSpamming = false; spamInterval = null; spamLog(t.spamStoppedLog); } } function cleanRoomCode(input) { if (!input) return ""; const match = input.match(/(?:\/|gartic\.io\/)([a-zA-Z0-9]{5,})(?:\/viewer)?$/); return match ? match[1] : input.trim(); } function startBots() { const t = translations[currentLang]; botCount = parseInt(document.getElementById('botCount').value) || 5; roomCode = cleanRoomCode(document.getElementById('roomCode').value.trim()); if (!roomCode) { alert(t.roomCodeInputLabel + ' ' + t.roomCodePlaceholder); return; } botsCreated = 0; botQueue = Array.from({ length: botCount }, (_, i) => i); isCreatingBot = false; log(`Starting ${botCount} bots for room ${roomCode}`); statusLog(t.startingBotsLog(botCount, roomCode)); document.getElementById('roomCodeDisplay').textContent = `${roomCode}`; updateButtonState(true); createNextBot(); startPeriodicMessage(); startAfkPrevention(); } function deleteAllBots() { const t = translations[currentLang]; if (socketList.length === 0) { statusLog(t.noBotsToDelete); updateButtonState(); return; } if (isSpamming) stopSpam(); clearInterval(afkInterval); afkInterval = null; socketList.forEach((socket, index) => { if (socket.readyState === WebSocket.OPEN && socket.playerId) { socket.send(`42[24,${socket.playerId}]`); statusLog(t.leaveCmdLog(index + 1, socket.playerId)); } }); } function createNextBot() { if (botQueue.length === 0 || isCreatingBot) { if (botQueue.length === 0 && !isCreatingBot && botsCreated > 0) { updateButtonState(); } return; } isCreatingBot = true; const index = botQueue.shift(); createIframe(index); } function createIframe(index) { const t = translations[currentLang]; statusLog(t.botCreatingLog(index + 1)); const iframe = document.createElement('iframe'); iframe.src = `https://gartic.io/${roomCode}`; iframe.style.display = 'none'; document.body.appendChild(iframe); currentIframe = iframe; iframe.onload = () => { const iw = iframe.contentWindow; setTimeout(() => { const playButton = iw.document.querySelector('.ic-playHome'); if (playButton) { playButton.click(); statusLog(t.playBtnLog(index + 1)); } else { statusLog(t.playBtnErrLog(index + 1)); cleanupIframe(); isCreatingBot = false; botsCreated++; createNextBot(); return; } GM_cookie.delete({ name: 'garticio' }, (error) => log(error ? `✖ Bot ${index+1} garticio cookie error` : `✔ Bot ${index+1} garticio cookie deleted`)); GM_cookie.delete({ name: 'cf_clearance' }, (error) => log(error ? `✖ Bot ${index+1} cf_clearance cookie error` : `✔ Bot ${index+1} cf_clearance cookie deleted`)); const originalXHROpen = iw.XMLHttpRequest.prototype.open; iw.XMLHttpRequest.prototype.open = function(m, u) { if (u.includes('server?check=')) this.isServerCheck = true; return originalXHROpen.apply(this, arguments); }; const originalXHRSend = iw.XMLHttpRequest.prototype.send; iw.XMLHttpRequest.prototype.send = function() { if (this.isServerCheck) { this.addEventListener('readystatechange', function() { if (this.readyState === 4 && this.status === 200) { try { const m = this.responseText.match(/(https:\/\/[^?]+)\?c=([^&]+)/); if (m) { websocketUrl = `wss://${m[1].replace('https://','')}/socket.io/?c=${m[2]}&EIO=3&transport=websocket`; statusLog(t.websocketUrlLog); createBotSocket(index, websocketUrl, index === 0); } else { statusLog(t.jsonErrLog(index+1)); cleanupIframe(); isCreatingBot=false; botsCreated++; createNextBot(); } } catch(e) { statusLog(t.jsonErrLog(index+1)); cleanupIframe(); isCreatingBot=false; botsCreated++; createNextBot(); } } }); } return originalXHRSend.apply(this, arguments); }; const originalSend = iw.WebSocket.prototype.send; iw.WebSocket.prototype.send = function(d) { if (typeof d === 'string' && d.startsWith('42[3,{')) { try { const p = JSON.parse(d.substring(2)); if(p[1]?.token){ token=p[1].token; sala=p[1].sala||roomCode; statusLog(t.credsLog(index+1)); document.getElementById('roomCodeDisplay').textContent=sala; return; } } catch(e){ statusLog(t.jsonErrLog(index+1)); cleanupIframe(); isCreatingBot=false; botsCreated++; createNextBot(); } } return originalSend.apply(this, arguments); }; }, 1500); }; iframe.onerror = () => { statusLog(t.iframeErrLog(index+1)); cleanupIframe(); isCreatingBot = false; botsCreated++; createNextBot(); }; } function cleanupIframe() { if (currentIframe) { currentIframe.remove(); currentIframe = null; statusLog(translations[currentLang].iframeRemovedLog); } } function isBot(p) { if (!p.nick) return false; const c = p.nick.replace(/[\u200B-\u200D\u2061-\u2063]/g, ''); return c === 'anonimbiri' || c === 'AnonimBiri'; } function createBotSocket(index, wsUrl, isFirstBot = false) { const t = translations[currentLang]; if (!wsUrl) { statusLog(t.websocketUrlLog); cleanupIframe(); isCreatingBot = false; botsCreated++; createNextBot(); return; } statusLog(t.wsConnectingLog(index + 1)); const ws = new WebSocket(wsUrl); ws.index = index; socketList.push(ws); ws.onopen = () => statusLog(t.wsOpenLog(index + 1)); ws.onmessage = (e) => { if (e.data === '40') { const n = insertInvisibleChar(isFirstBot ? 'AnonimBiri' : 'anonimbiri'); ws.send(`42[3,{"v":20000,"token":"${token}","nick":"${n}","avatar":"","platform":0,"sala":"${sala}"}]`); statusLog(t.wsJoinedLog(index + 1, n)); } if (e.data === '42["6",3]') { statusLog(t.wsRoomFullLog(index + 1)); botQueue = []; cleanupIframe(); isCreatingBot = false; updateButtonState(); return; } if (e.data === '42["6",4]') { alert(t.wsInGameLog(index + 1, roomCode)); statusLog(t.wsInGameLog(index + 1, roomCode)); botQueue = []; cleanupIframe(); isCreatingBot = false; updateButtonState(); return; } if (e.data.startsWith('42["5",')) { try { const p = JSON.parse(e.data.substring(2)); ws.playerId = p[2]; ws.send(`42[46,${ws.playerId}]`); statusLog(t.wsReadyLog(index + 1)); if (p[2] && Array.isArray(p[5])) { const ri=p[4], np=p[5].filter(pl => !isBot(pl)); playerList=updatePlayerListNoDuplicates(np); document.getElementById('roomTheme').textContent=ri.tema||t.noTheme; updatePlayerListUI(); } cleanupIframe(); isCreatingBot=false; botsCreated++; if (botQueue.length === 0) { updateButtonState(); statusLog(t.allBotsSuccessLog(botCount)); } createNextBot(); } catch (er) { statusLog(t.wsDataErrLog(index + 1)); cleanupIframe(); isCreatingBot=false; botsCreated++; createNextBot(); } } if (e.data === '42["6",null]') { statusLog(t.wsLeaveConfirmLog(index + 1)); socketList=socketList.filter(s=>s!==ws); if(ws.readyState===WebSocket.OPEN)ws.close(); if(socketList.length===0)updateButtonState(); } if (typeof e.data === 'string') { try { if(e.data.startsWith('42["23",')) { const np=JSON.parse(e.data.substring(2))[1]; if(np&&np.id&&!isBot(np)&&!playerList.some(p=>String(p.id)===String(np.id))){ playerList.push(np); updatePlayerListUI(); statusLog(t.newPlayerLog(np.nick)); } } if(e.data.startsWith('42["24",')) { const lpi=JSON.parse(e.data.substring(2))[1]; playerList=playerList.filter(p=>String(p.id)!==String(lpi)); updatePlayerListUI(); statusLog(t.playerLeftLog(lpi)); } if(e.data.startsWith('42["16",')) { const p=JSON.parse(e.data.substring(2)), o=[p[1],p[3]], ci=Math.floor(Math.random()*2), c=o[ci]; botChoices.set(ws.playerId,c); log(`Bot ${index} chose ${c}`); setTimeout(()=>{if(ws.readyState===WebSocket.OPEN&&ws.playerId)ws.send(`42[34,${ws.playerId},${ci}]`);}, 8000); } if (e.data.startsWith('42["34",')) { if (ws.readyState === WebSocket.OPEN && ws.playerId) { for(let i=0; i<4; i++) ws.send(`42[30,${ws.playerId}]`); log(`Bot ${index}: Confirmed choice. Sent ready signals.`); const choice = botChoices.get(ws.playerId); if (choice) { setTimeout(() => { socketList.forEach((otherSocket) => { if (otherSocket !== ws && otherSocket.readyState === WebSocket.OPEN && otherSocket.playerId) { otherSocket.send(`42[13,${otherSocket.playerId},"${choice}"]`); log(`Bot ${index}: Sent choice "${choice}" to bot ${otherSocket.index+1}`); } }); }, 1000); // 1 second delay } } } } catch(er) { log(`Bot ${index}: Error parsing update: ${er}`, true); } } }; ws.onerror = () => { statusLog(t.wsErrorLog(index + 1)); socketList=socketList.filter(s=>s!==ws); cleanupIframe(); isCreatingBot = false; botsCreated++; createNextBot(); }; ws.onclose = () => { statusLog(t.wsCloseLog(index + 1)); socketList=socketList.filter(s=>s!==ws); cleanupIframe(); isCreatingBot = false; createNextBot(); if(socketList.length===0)updateButtonState(); }; } function updatePlayerListNoDuplicates(np) { const e=new Set(playerList.map(p=>String(p.id))), u=[...playerList]; np.forEach(p=>{if(!e.has(String(p.id))){u.push(p);e.add(String(p.id));}}); return u; } function updatePlayerListUI() { const t = translations[currentLang], el = document.getElementById('playerList'); if (!playerList || playerList.length === 0) { el.innerHTML = `
${t.noPlayers}
`; return; } el.innerHTML = playerList.map(p => `
${p.nick}
${t.points}: ${p.pontos||0} | ${t.wins}: ${p.vitorias||0}
`).join(''); el.querySelectorAll('.kick-btn').forEach(b => b.addEventListener('click', function() { kickPlayer(this.dataset.id); })); } function kickPlayer(pId) { const t=translations[currentLang]; if(socketList.length===0){statusLog(t.noBotsToKick);return;} if(pId){socketList.forEach((s,i)=>{if(s.readyState===WebSocket.OPEN&&s.playerId){s.send(`42[45,${s.playerId},["${pId}",true]]`);statusLog(t.kickSentLog(pId, i+1));}});}else{statusLog(t.kickFailLog);} } function reportDrawing() { const t=translations[currentLang]; if(socketList.length===0){statusLog(t.noBotsToKick);return;} socketList.forEach((s,i)=>{if(s.readyState===WebSocket.OPEN&&s.playerId){s.send(`42[35,${s.playerId}]`); statusLog(`${t.reportDrawingBtn} request sent (Socket ${i+1})`);}}); } function getAvatarUrl(p) { if (p.foto) return p.foto; if (p.avatar !== undefined && p.avatar !== null) return `https://gartic.io/static/images/avatar/svg/${p.avatar}.svg`; return 'https://gartic.io/static/images/avatar/svg/0.svg'; } function startPeriodicMessage() { setInterval(()=>{socketList.forEach(s=>{if(s.readyState===WebSocket.OPEN&&s.playerId)s.send(`42[42,${s.playerId}]`);});}, 20000); } function startAfkPrevention() { if (afkInterval) clearInterval(afkInterval); afkInterval = setInterval(() => { if (socketList.length > 0) { const randomBot = socketList[Math.floor(Math.random() * socketList.length)]; if (randomBot && randomBot.readyState === WebSocket.OPEN && randomBot.playerId) { const adText = insertInvisibleChar("bot link: ") + "https://greasyfork.org/en/scripts/533419-gartic-anonimbiri-bot-panel"; randomBot.send(`42[11,${randomBot.playerId},"${adText}"]`); log(`Bot ${randomBot.index + 1} sent AFK prevention message.`); } } }, 30000); // Send every 30 seconds } // --- INITIALIZATION --- function initialize() { startBotsButton.addEventListener('click', () => { (startBotsButton.textContent === translations[currentLang].startBotsBtn) ? startBots() : deleteAllBots(); }); document.getElementById('startSpam').addEventListener('click', () => { (document.getElementById('startSpam').textContent === translations[currentLang].startSpamBtn) ? startSpam() : stopSpam(); }); document.getElementById('reportDrawing').addEventListener('click', reportDrawing); initCustomUI(); const browserLang = navigator.language.split('-')[0]; setLanguage(translations[browserLang] ? browserLang : 'tr'); const lastPart = window.location.pathname.split('/').pop(); if (lastPart && lastPart !== 'anonimbiri') { const cleanedCode = cleanRoomCode(lastPart); document.getElementById('roomCode').value = cleanedCode; if (cleanedCode) statusLog(translations[currentLang].urlExtractedLog(cleanedCode)); } log("Gartic Anonimbiri Bot Panel v2025-05-08 initialized"); statusLog(translations[currentLang].initLog); } initialize(); })();