PokeRogue - Autoplay (basic)

Autoplay helper for PokeRogue: auto-progress and basic auto-battle. Use responsibly (single-player / local saves only).

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         PokeRogue - Autoplay (basic)
// @namespace    http://tampermonkey.net/
// @version      0.9
// @description  Autoplay helper for PokeRogue: auto-progress and basic auto-battle. Use responsibly (single-player / local saves only).
// @author       Generated with ChatGPT
// @match        https://pokerogue.net/*
// @grant        none
// @run-at       document-idle
// ==/UserScript==

(function() {
    'use strict';

    // CONFIG
    const CONFIG = {
        pollInterval: 300,        // ms between checks
        thinkDelay: 300,          // delay before making a move (ms)
        preferHighestPower: true, // choose move with highest power if data available
        autoUseItems: false,      // whether to try to auto-use items from menu
        stopOnLevelUp: false,     // pause autoplay if party levels up
    };

    // internal state
    let running = false;
    let loopHandle = null;

    function log(...args){ console.log('[ARBOT]',...args); }

    // try to safely find the main scene/game object
    function findScene(){
        // common places found by community scripts
        if (window.scene) return window.scene;
        if (window.game && window.game.scene) return window.game.scene;
        if (globalThis?.pokerogue?.getScene) return globalThis.pokerogue.getScene();
        // scan globals for an object that looks like starterData/dexData
        for (const k of Object.keys(window)){
            try{
                const v = window[k];
                if (v && typeof v === 'object'){
                    if ('starterData' in v && 'dexData' in v) return v;
                }
            }catch(e){}
        }
        return null;
    }

    // helpers to simulate clicks on UI elements (buttons that appear in the DOM)
    function clickElement(el){ if(!el) return false; el.dispatchEvent(new MouseEvent('mousedown',{bubbles:true})); el.dispatchEvent(new MouseEvent('mouseup',{bubbles:true})); el.click(); return true; }

    // try to advance dialogue / continue screens
    function tryAdvanceUI(){
        // Usually the game shows "Next" or continues on space/enter; try to click primary button
        const primary = document.querySelector('.dialogue-button, .primary, button.primary, button');
        if(primary){ clickElement(primary); return true; }
        // fallback: press space
        const evt = new KeyboardEvent('keydown', { key: ' ', code: 'Space', bubbles: true });
        document.dispatchEvent(evt);
        return false;
    }

    // basic battle decision logic - best-effort: inspect party and active battle object
    function autoBattle(scene){
        try{
            // community scripts expose scene.fight or scene.battle or scene.battleData
            const battle = scene.fight || scene.battle || scene.battleData || (scene.scene && (scene.scene.fight||scene.scene.battle));
            if(!battle) return false;

            // find active pokemon and available moves
            const active = battle.activePokemon || battle.activePoke || (battle.player && battle.player.active);
            const options = battle.moves || active?.moves || (battle.moveOptions);

            // if there are DOM buttons for moves, try to click best one
            const moveButtons = Array.from(document.querySelectorAll('.move-button, .battle-move, button.move')).filter(Boolean);
            if(moveButtons.length>0){
                // choose button index using simple heuristic
                let bestIndex = 0;
                if(options && options.length === moveButtons.length){
                    let bestScore = -Infinity;
                    for(let i=0;i<options.length;i++){
                        const m = options[i];
                        // estimate power from fields 'power' 'damage' or 'basePower'
                        const power = Number(m?.power ?? m?.damage ?? m?.basePower ?? 0);
                        const acc = Number(m?.accuracy ?? 100);
                        let score = power * (acc/100);
                        // prefer non-damaging moves less
                        if(m?.category === 'status') score *= 0.5;
                        if(score>bestScore){ bestScore = score; bestIndex = i; }
                    }
                }
                // click chosen move after small delay
                setTimeout(()=> clickElement(moveButtons[bestIndex]), CONFIG.thinkDelay);
                return true;
            }

            // fallback: if battle has a method to choose move, call it
            if(typeof battle.chooseMove === 'function'){
                // try to select by highest power
                const moves = battle.moves || active?.moves || [];
                let idx = 0;
                if(moves.length){
                    let best = -Infinity;
                    for(let i=0;i<moves.length;i++){
                        const m = moves[i];
                        const p = Number(m?.power ?? m?.damage ?? 0);
                        if(p>best){ best = p; idx = i; }
                    }
                }
                setTimeout(()=> { try{ battle.chooseMove(idx); }catch(e){/*ignore*/} }, CONFIG.thinkDelay);
                return true;
            }

        }catch(e){ /* ignore */ }
        return false;
    }

    function mainLoop(){
        const scene = findScene();
        if(!scene){ return; }

        // If currently in battle/selection, try to auto-battle
        if(autoBattle(scene)){ return; }

        // otherwise try to advance UI (menus, dialogue, shop screens)
        tryAdvanceUI();
    }

    // public controls (exposed on window for quick toggling)
    function start(){ if(running) return; running = true; log('autoplay started'); loopHandle = setInterval(mainLoop, CONFIG.pollInterval); }
    function stop(){ if(!running) return; running = false; clearInterval(loopHandle); loopHandle = null; log('autoplay stopped'); }

    // expose controls
    globalThis.PokeRogueAutoplay = { start, stop, running: () => running, CONFIG };

    // small UI hint on page
    const badge = document.createElement('div');
    badge.textContent = 'AR-BOT';
    Object.assign(badge.style, {position:'fixed',right:'8px',bottom:'8px',padding:'6px 8px',background:'#111',color:'#fff',zIndex:99999,fontSize:'12px',borderRadius:'6px',opacity:0.6,cursor:'pointer'});
    badge.title = 'Click to toggle autoplay (or use PokeRogueAutoplay.start()/stop() in console)';
    badge.onclick = ()=>{ running? stop():start(); badge.style.background = running? '#a00' : '#111'; };
    document.body.appendChild(badge);

    log('Autoplay helper injected. Use PokeRogueAutoplay.start() to begin.');

})();