Wikigacha Auto Player

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

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==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);
  });

})();