Wikigacha Auto Player

Automatically opens packs, watches ads, and selects the best 10 cards for daily raid battles on wikigacha.com

Você precisará instalar uma extensão como Tampermonkey, Greasemonkey ou Violentmonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey ou Violentmonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey ou Userscripts para instalar este script.

Você precisará instalar uma extensão como o Tampermonkey para instalar este script.

Você precisará instalar um gerenciador de scripts de usuário para instalar este script.

(Eu já tenho um gerenciador de scripts de usuário, me deixe instalá-lo!)

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

(Eu já possuo um gerenciador de estilos de usuário, me deixar fazer a instalação!)

// ==UserScript==
// @name        Wikigacha Auto Player
// @description Automatically opens packs, watches ads, and selects the best 10 cards for daily raid battles on wikigacha.com
// @match       https://wikigacha.com/*
// @grant       none
// @run-at      document-start
// @version 0.0.1.20260322204210
// @namespace https://greasyfork.org/users/1583423
// ==/UserScript==

(function () {
  'use strict';

  // Inject alert override directly into page context
  const script = document.createElement('script');
  script.textContent = `
    window.alert = function(msg) {
      console.log('[Wikigacha] Alert suppressed:', msg);
    };
    window.confirm = function() { return true; };
  `;
  (document.head || document.documentElement).appendChild(script);
  script.remove();

  const INTERVAL = 300;
  const SCAN_RARITIES = ['LR', 'UR'];

  function findButtonByText(text) {
    return [...document.querySelectorAll('button')].find(
      b => b.textContent.trim().toLowerCase() === text.toLowerCase()
    );
  }

  function tryOpenPack() {
    const pack = document.querySelector('img[alt="Wiki Pack"]');
    if (pack) {
      pack.closest('button, div[role="button"], div')?.click() || pack.click();
      return true;
    }
    const tapBtn = [...document.querySelectorAll('*')].find(
      el => el.textContent.trim() === '▲ TAP TO OPEN ▲'
    );
    if (tapBtn) { tapBtn.click(); return true; }
    return false;
  }

  function tryWatchAd() {
    const adBtn = [...document.querySelectorAll('span')].find(
      s => s.textContent.trim() === '📺 Watch Ad to Refill'
    );
    if (adBtn) { adBtn.closest('button')?.click() || adBtn.click(); return true; }
    return false;
  }

  function tryCloseAd() {
    const closeBtn = findButtonByText('Close Ad');
    if (closeBtn) { closeBtn.click(); return true; }
    return false;
  }

  function tryBackToPacks() {
    const backBtn = findButtonByText('BACK TO PACKS');
    if (backBtn) { backBtn.click(); return true; }
    return false;
  }

  function tryRecoverFromError() {
    const collectionBtn = [...document.querySelectorAll('button')].find(
      b => b.textContent.trim() === 'Collection'
    );
    if (collectionBtn) {
      collectionBtn.click();
      setTimeout(() => {
        const packsBtn = [...document.querySelectorAll('button')].find(
          b => b.textContent.trim() === 'Packs'
        );
        if (packsBtn) packsBtn.click();
      }, 1500);
      return true;
    }
    return false;
  }

  // ── RAID AUTO-SELECT ────────────────────────────────────────────────

  let raidRunning = false;

  async function sleep(ms) {
    return new Promise(r => setTimeout(r, ms));
  }

  function getRowsFromPage() {
    return [...document.querySelectorAll('tbody tr')].map(row => {
      const cells = row.querySelectorAll('td');
      if (cells.length < 6) return null;
      const rarity = cells[2]?.textContent.trim();
      const atk = parseInt(cells[4]?.textContent.trim().replace(/,/g, ''), 10) || 0;
      const def = parseInt(cells[5]?.textContent.trim().replace(/,/g, ''), 10) || 0;
      const plusBtn = cells[0]?.querySelector('button:last-child');
      return { rarity, atk, def, total: atk + def, plusBtn };
    }).filter(Boolean);
  }

  async function collectAllCards() {
    let allCards = [];

    // Reset to page 1
    while (true) {
      const prevBtn = [...document.querySelectorAll('button')].find(b => b.textContent.trim() === 'Prev');
      if (!prevBtn || prevBtn.disabled) break;
      prevBtn.click();
      await sleep(600);
    }

    while (true) {
      await sleep(500);
      const rows = getRowsFromPage();
      let hitLowerRarity = false;

      for (const row of rows) {
        if (!SCAN_RARITIES.includes(row.rarity)) {
          hitLowerRarity = true;
          break;
        }
        allCards.push(row);
      }

      if (hitLowerRarity) {
        console.log(`[Wikigacha] Hit lower rarity, stopping scan with ${allCards.length} cards`);
        break;
      }

      const nextBtn = [...document.querySelectorAll('button')].find(b => b.textContent.trim() === 'Next');
      if (!nextBtn || nextBtn.disabled) break;
      nextBtn.click();
    }

    return allCards;
  }

  async function autoSelectBestRaid() {
    if (raidRunning) return;
    raidRunning = true;
    console.log('[Wikigacha] Starting raid auto-select...');

    // Reset any existing selection first
    const resetBtn = findButtonByText('Reset');
    if (resetBtn) { resetBtn.click(); await sleep(400); }

    const allCards = await collectAllCards();
    console.log(`[Wikigacha] Scraped ${allCards.length} LR/UR cards`);

    // Sort by ATK+DEF descending, pick top 10 with available + button
    const top10 = allCards
      .filter(c => c.plusBtn && !c.plusBtn.disabled)
      .sort((a, b) => b.total - a.total)
      .slice(0, 10);

    console.log('[Wikigacha] Top 10 by ATK+DEF:', top10.map(c => `${c.rarity} ${c.total}`));

    // Reset to page 1 again to start clicking
    while (true) {
      const prevBtn = [...document.querySelectorAll('button')].find(b => b.textContent.trim() === 'Prev');
      if (!prevBtn || prevBtn.disabled) break;
      prevBtn.click();
      await sleep(600);
    }

    // Click + for each top 10 card by matching stats page by page
    let remaining = [...top10];

    while (remaining.length > 0) {
      await sleep(500);
      const rows = getRowsFromPage();

      for (const row of rows) {
        const match = remaining.findIndex(
          c => c.atk === row.atk && c.def === row.def && row.plusBtn && !row.plusBtn.disabled
        );
        if (match !== -1) {
          row.plusBtn.click();
          remaining.splice(match, 1);
          await sleep(150);
        }
      }

      if (remaining.length === 0) break;

      // Stop paginating once we're past LR/UR
      const rows2 = getRowsFromPage();
      const hitLower = rows2.some(r => !SCAN_RARITIES.includes(r.rarity));
      if (hitLower) break;

      const nextBtn = [...document.querySelectorAll('button')].find(b => b.textContent.trim() === 'Next');
      if (!nextBtn || nextBtn.disabled) break;
      nextBtn.click();
    }

    console.log('[Wikigacha] Raid selection done!');
    raidRunning = false;
  }

  function injectRaidButton() {
    if (document.getElementById('wg-raid-btn')) return;
    const target = [...document.querySelectorAll('button')].find(b => b.textContent.trim() === 'Back to Raid Top');
    if (!target) return;

    const btn = document.createElement('button');
    btn.id = 'wg-raid-btn';
    btn.textContent = '⚔️ Auto-Select Best 10';
    btn.style.cssText = `
      margin-left: 8px;
      padding: 4px 14px;
      border-radius: 9999px;
      border: 1px solid #22d3ee;
      background: rgba(8,145,178,0.2);
      color: #cffafe;
      font-size: 13px;
      cursor: pointer;
    `;
    btn.addEventListener('click', autoSelectBestRaid);
    target.parentElement.appendChild(btn);
  }

  // ── MAIN LOOP ────────────────────────────────────────────────────────

  let stuckCounter = 0;

  window.addEventListener('load', () => {
    setInterval(() => {
      injectRaidButton();

      if (raidRunning) return;

      if (tryCloseAd()) { stuckCounter = 0; return; }
      if (tryBackToPacks()) { stuckCounter = 0; return; }
      if (tryWatchAd()) { stuckCounter = 0; return; }
      if (tryOpenPack()) { stuckCounter = 0; return; }

      stuckCounter++;
      if (stuckCounter >= 5) {
        const onPackPage = !!document.querySelector('img[alt="Wiki Pack"]') ||
          [...document.querySelectorAll('span')].some(s => s.textContent.trim() === '📺 Watch Ad to Refill');
        if (onPackPage) {
          console.log('[Wikigacha] Stuck on pack page, attempting recovery...');
          tryRecoverFromError();
        }
        stuckCounter = 0;
      }
    }, INTERVAL);
  });

})();