// ==UserScript== // @name 榭洛科特的背包 Beta // @version 0.1.1 // @author Alk // @license GPL-3.0 // @description 榭洛科特的背包测试版 // @description 仅控制浏览器,不对游戏进行任何操作。 // @description Sierokarte's BackPack Beta Version. This script only affects the browser, does nothing to GBF game. // @match *.granbluefantasy.jp // @grant unsafeWindow // @grant GM_registerMenuCommand // @grant GM_setValue // @grant GM_getValue // @run-at document-start // @namespace https://greasyfork.org/users/1455240 // @icon https://raw.githubusercontent.com/enorsona/thirdparty/refs/heads/master/sherurotes_carrybag.ico // @downloadURL none // ==/UserScript== (function () { 'use strict'; // 战斗结果 JSON 文件名集合 const battleSet = new Set([ 'normal_attack_result.json', 'ability_result.json', 'fatal_chain_result.json', 'summon_result.json' ]); // 配置默认值 const defaults = { refresh_attack: true, hide_left_sb: false, hide_right_sb: false, refresh_koenig_dekret: true, refresh_coronal_ejection: false, refresh_secret_triad: false, hunter_mode: false, replace_refresh_with_back: false, allow_auto_redirect: false, auto_redirect_hash: '' }; // 获取配置值 function getCfg(key) { return GM_getValue(key, defaults[key]); } // 切换配置并刷新页面 function toggleCfg(key) { const val = !getCfg(key); GM_setValue(key, val); // 切换后立即刷新以生效 window.location.reload(); } // 注册右键菜单 const labels = { refresh_attack: '攻击后自动刷新', hide_left_sb: '关闭左侧边栏', hide_right_sb: '关闭右侧边栏', refresh_koenig_dekret: '帝王法令刷新', refresh_coronal_ejection: '日冕喷发刷新', refresh_secret_triad: '万事皆三刷新', hunter_mode: '猎金模式', replace_refresh_with_back: '替换刷新为后退', allow_auto_redirect: '自动跳转' }; Object.entries(labels).forEach(([key, label]) => { GM_registerMenuCommand( `${label}:${getCfg(key) ? '已开启' : '已关闭'}`, () => toggleCfg(key) ); }); // 页面加载后隐藏侧栏 window.addEventListener('load', () => { if (!/mobile/.test(navigator.userAgent.toLowerCase())) { if (getCfg('hide_left_sb')) { document.body.firstElementChild?.firstElementChild?.remove(); } } if (getCfg('hide_right_sb')) { document.querySelector('#submenu')?.remove(); } }); // 自动跳转 if (getCfg('allow_auto_redirect')) { const doRedirect = () => { if (location.hash.startsWith('#result_multi')) { const target = GM_getValue('auto_redirect_hash', defaults.auto_redirect_hash); if (target) location.href = `${location.origin}/${target}`; } }; window.addEventListener('load', () => setTimeout(doRedirect, Math.random() * 1000 + 100)); window.addEventListener('popstate', () => setTimeout(doRedirect, Math.random() * 1000 + 100)); } // 跳转控制 function reload() { if (getCfg('replace_refresh_with_back')) return goBack(); setTimeout(() => location.reload(), Math.random() * 150 + 50); } function goBack() { setTimeout(() => history.go(-1), Math.random() * 150 + 50); } // 战斗处理逻辑 function handleBattle(scenario, urlKey) { const winObj = scenario.find(o => o.cmd === 'win'); const winStatus = winObj ? (winObj.is_last_raid === 1 ? 'raid' : 'battle') : 'continue'; if (winStatus === 'raid') return goBack(); if (winStatus === 'battle') return reload(); if (urlKey === 'normal_attack_result.json' && getCfg('refresh_attack')) return reload(); if (urlKey === 'ability_result.json') { const ability = scenario.find(o => o.cmd === 'ability'); if (ability) { if ((getCfg('refresh_koenig_dekret') && ability.name === 'ケーニヒ・ベシュテレン') || (getCfg('refresh_coronal_ejection') && ability.name.includes('攻撃行動') && ability.name.includes('2回')) || (getCfg('refresh_secret_triad') && ability.name === 'シークレットトライアド')) { return reload(); } } } if ((urlKey === 'fatal_chain_result.json' || urlKey === 'summon_result.json') && getCfg('refresh_attack')) { return reload(); } } // 拦截 XHR const origSend = unsafeWindow.XMLHttpRequest.prototype.send; unsafeWindow.XMLHttpRequest.prototype.send = function (...args) { this.addEventListener('load', () => { try { const url = new URL(this.responseURL); const key = url.pathname.split('/')[3]; if (!battleSet.has(key)) return; const resp = JSON.parse(this.responseText); const scenario = resp.scenario || resp; handleBattle(scenario, key); } catch (e) { console.warn('脚本出错:', e); } }); origSend.apply(this, args); }; })();