Greasy Fork

Greasy Fork is available in English.

榭洛科特的背包

原名GBF周回本胜利跳过。已重构。现支持:1.关闭左/右侧边栏,2.攻击后刷新,3.胜利跳过,4.帝王指令自动刷新,5.太阳自动刷新 待追加:6.五神复活增益显示。

当前为 2025-07-30 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name                榭洛科特的背包
// @version             1.7.0.2
// @author              Alk
// @license             GPL3.0
// @description         原名GBF周回本胜利跳过。已重构。现支持:1.关闭左/右侧边栏,2.攻击后刷新,3.胜利跳过,4.帝王指令自动刷新,5.太阳自动刷新 待追加:6.五神复活增益显示。
// @match               *.granbluefantasy.jp
// @grant               unsafeWindow
// @grant               GM_registerMenuCommand
// @grant               GM_setValue
// @grant               GM_getValue
// @run-at              document-start
// @namespace           http://greasyfork.icu/users/1455240
// @icon                https://raw.githubusercontent.com/enorsona/thirdparty/refs/heads/master/sherurotes_carrybag.ico
// ==/UserScript==

// ========== 设置项 ==========
const battle_json_names = ['normal_attack_result.json', 'ability_result.json', 'fatal_chain_result.json', 'summon_result.json']
const settings_strings = {
    refresh_attack: 'AttackRefresh',
    hide_left_sb: 'HideLeftSidebar',
    hide_right_sb: 'HideRightSidebar',
    refresh_koenig_dekret: 'KoenigDekretRefresh',
    refresh_coronal_ejection: 'CoronalEjection',
    replace_refresh_with_back: 'ReplaceRefreshWithBack',
    allow_auto_redirect: 'AllowAutoRedirect',
    auto_redirect_url: 'AutoRedirectURL',
}

// ========== 状态读取 ==========
const checkEnabledAttackRefresh = () => {
    return GM_getValue(settings_strings.refresh_attack, true);
};
const checkEnabledHideLeftSidebar = () => {
    return GM_getValue(settings_strings.hide_left_sb, false);
};
const checkEnabledHideRightSidebar = () => {
    return GM_getValue(settings_strings.hide_right_sb, false);
};
const checkEnabledKoenigDekretAutoRefresh = () => {
    return GM_getValue(settings_strings.refresh_koenig_dekret, true);
};
const checkEnabledCoronalEjectionAutoRefresh = () => {
    return GM_getValue(settings_strings.refresh_coronal_ejection, true);
};
const checkEnabledReplaceRefreshWithBack = () => {
    return GM_getValue(settings_strings.replace_refresh_with_back, false);
}
const checkAllowAutoRedirect = () => {
    return GM_getValue(settings_strings.allow_auto_redirect, false);
}
const checkAutoRedirectURL = () => {
    return GM_getValue(settings_strings.auto_redirect_url, 0);
}

let rrwb_enabled = checkEnabledReplaceRefreshWithBack();
let ar_enabled = checkEnabledAttackRefresh();
let kdr_enabled = checkEnabledKoenigDekretAutoRefresh();
let cer_enabled = checkEnabledCoronalEjectionAutoRefresh();
let aar_enabled = checkAllowAutoRedirect();

// ========== 切换刷新功能 ==========
const switchEnabledAttackRefresh = () => {
    const current = checkEnabledAttackRefresh();
    GM_setValue(settings_strings.refresh_attack, !current);
    reload();
};
const switchEnabledHideLeftSidebar = () => {
    const current = checkEnabledHideLeftSidebar();
    GM_setValue(settings_strings.hide_left_sb, !current);
    reload();
};
const switchEnabledHideRightSidebar = () => {
    const current = checkEnabledHideRightSidebar();
    GM_setValue(settings_strings.hide_right_sb, !current);
    reload();
};
const switchEnabledKoenigDekretAutoRefresh = () => {
    const current = checkEnabledKoenigDekretAutoRefresh();
    GM_setValue(settings_strings.refresh_koenig_dekret, !current);
    reload();
};
const switchEnabledCoronalEjectionAutoRefresh = () => {
    const current = checkEnabledCoronalEjectionAutoRefresh();
    GM_setValue(settings_strings.refresh_coronal_ejection, !current);
    reload();
};
const switchEnabledReplaceRefreshWithBack = () => {
    const current = checkEnabledReplaceRefreshWithBack();
    GM_setValue(settings_strings.replace_refresh_with_back, !current);
    reload();
};
const switchAllowAutoRedirect = () => {
    const current = checkAllowAutoRedirect();
    GM_setValue(settings_strings.allow_auto_redirect, !current);
    reload();
};
const getAutoRedirectURL = () => {
    const current = location.hash;
    GM_setValue(settings_strings.auto_redirect_url, current);
    reload();
}

// ========== 注册菜单 ==========
const registerMenu = () => {
    GM_registerMenuCommand(
        `启用替换刷新为后退:${checkEnabledReplaceRefreshWithBack() ? '已开启' : '已关闭'}`,
        switchEnabledReplaceRefreshWithBack
    );
    GM_registerMenuCommand(
        `启用自动跳转至召唤选择界面:${checkAllowAutoRedirect() ? '已开启' : '已关闭'}`,
        switchAllowAutoRedirect
    );
    GM_registerMenuCommand(
        `当前召唤石选择界面URL:${checkAutoRedirectURL()}`,
        getAutoRedirectURL
    );
    GM_registerMenuCommand(
        `攻击后自动刷新:${checkEnabledAttackRefresh() ? '已开启' : '已关闭'}`,
        switchEnabledAttackRefresh
    );
    GM_registerMenuCommand(
        `关闭左侧边栏:${checkEnabledHideLeftSidebar() ? '已开启' : '已关闭'}`,
        switchEnabledHideLeftSidebar
    );
    GM_registerMenuCommand(
        `关闭右侧边栏:${checkEnabledHideRightSidebar() ? '已开启' : '已关闭'}`,
        switchEnabledHideRightSidebar
    );
    GM_registerMenuCommand(
        `启用帝王指令刷新:${checkEnabledKoenigDekretAutoRefresh() ? '已开启' : '已关闭'}`,
        switchEnabledKoenigDekretAutoRefresh
    );
    GM_registerMenuCommand(
        `启用太阳召唤刷新:${checkEnabledCoronalEjectionAutoRefresh() ? '已开启' : '已关闭'}`,
        switchEnabledCoronalEjectionAutoRefresh
    );
};
registerMenu();

// ========== 工具 ==========
const checkIsMobile = () => {
    const userAgent = navigator.userAgent.toLowerCase();
    return /iphone|ipad|android|mobile|windows phone|blackberry/.test(userAgent);
};
const getRandomInt = (min, max) => {
    return Math.floor(Math.random() * (max - min + 1)) + min;
}


// ========== URL 与 JSON 解析 ==========
const tryParseJSON = (response) => {
    try {
        return JSON.parse(response);
    } catch (e) {
        return response;
    }
};

const checkURL = (base) => {
    const url = new URL(base);
    const parts = url.pathname.split('/');
    return {
        is_battle: battle_json_names.includes(parts[3]),
        is_attack: parts[3] === battle_json_names[0],
        is_skill: parts[3] === battle_json_names[1],
        is_fc: parts[3] === battle_json_names[2],
        is_summon: parts[3] === battle_json_names[3],
    };
};
const checkWin = (scenario) => {
    const win = scenario.find(s => s.cmd === "win");
    if (win) {
        return win.is_last_raid === 1 ? 1 : 2;
    }
    return 0;
};
const checkIsKoenigDekret = (scenario) => {
    return (
        scenario[0].cmd === 'ability'
        && scenario[0].voice === 'voice/3040425000_ability_us2.mp3'
        && scenario[0].name === 'ケーニヒ・ベシュテレン'
    ) || false;
}
const checkIsCoronalEjection = (scenario) => {
    return (
        scenario[2].cmd === 'ability'
        && scenario[2].name === '火属性ダメージ/3番目までに配置された火属性キャラがターン進行時に攻撃行動を2回行う'
    ) || false;
}

// ========== 页面控制函数 ==========
const reload = () => {
    if (rrwb_enabled) {
        goback();
    } else {
        setTimeout(() => {
            location.reload(true);
        }, getRandomInt(0, 200))
    }
}
const goback = () => {
    setTimeout(() => {
        history.go(-1);
    }, getRandomInt(0, 200))
}
const aar = () => {
    const hash = location.hash.split('/')[0];
    const target = '#result_multi';
    console.log(hash, target);
    if(hash === target) {
        const aru = checkAutoRedirectURL();
        if (aru !== 0) {
            location.href = location.origin + '/' + aru;
        }
    }
}

// ========== 拦截并处理XHR ==========
const customLoad = (xhr, result) => {
    const response = tryParseJSON(xhr.response);
    const status = checkWin(response.scenario);

    if (status === 1) {
        goback();
    } else if (status === 0) {
        if (result.is_attack && ar_enabled) {
            reload();
        } else if (kdr_enabled && checkIsKoenigDekret(response.scenario)) {
            reload()
        } else if (cer_enabled && checkIsCoronalEjection(response.scenario)) {
            reload();
        }
    } else {
        reload();
    }
};

// ========== Hook XMLHttpRequest ==========
const origSend = unsafeWindow.XMLHttpRequest.prototype.send;
unsafeWindow.XMLHttpRequest.prototype.send = function (...args) {
    this.addEventListener('load', () => {
        const checkURLResult = checkURL(this.responseURL);
        const process_needed = checkURLResult.is_battle;
        if (process_needed) {
            customLoad(this, checkURLResult);
        }
    });
    origSend.apply(this, args);
};

// ========== 隐藏左侧边栏 ==========
(() => {
    if (checkIsMobile()) return;
    if (checkEnabledHideLeftSidebar()) {
        window.addEventListener('load', () => {
            try {
                const target = document.body.firstElementChild;
                if (target && target.firstElementChild) {
                    target.removeChild(target.firstElementChild);
                }
            } catch (e) {
                console.warn('隐藏左边栏失败:', e);
            }
        });
    }
})();
(() => {
    if (checkEnabledHideRightSidebar()) {
        window.addEventListener('load', () => {
            try {
                const target = document.querySelector('div#submenu');
                if (target) {
                    target.remove();
                }
            } catch (e) {
                console.warn('隐藏右边栏失败:', e);
            }
        });
    }
})();
(() => {
    if(aar_enabled) {
        window.onload = () => {
            aar()
        }
        window.addEventListener('popstate', () =>
            {
                if(checkAllowAutoRedirect()) {
                    setTimeout(aar, getRandomInt(100, 500))
                }
            }
        )
    }
})();