Gooboo宝藏预测器

为Gooboo游戏添加宝藏预测功能

// ==UserScript==
// @name         Gooboo宝藏预测器
// @namespace    http://tampermonkey.net/
// @version      1.1.0
// @description  为Gooboo游戏添加宝藏预测功能
// @author       Zding
// @match        *://gooboo.*/*
// @match        *://*/*gooboo*
// @exclude      https://gooboo.0nz.de/*
// @exclude      https://zdplay.github.io/gooboo/*
// @grant        none
// @license MIT
// @require      https://cdnjs.cloudflare.com/ajax/libs/seedrandom/3.0.5/seedrandom.min.js
// ==/UserScript==

//说明:在宝藏【购买】按钮的鼠标提示里
(function() {
    'use strict';

    const waitGame = () => new Promise(r => {
        const c = () => {
            try {
                const s = document.getElementsByClassName("primary")[0]?.__vue__?.$store;
                s && s.state.system.playerId ? r(s) : setTimeout(c, 1000);
            } catch (e) { setTimeout(c, 1000); }
        };
        c();
    });

    const predict = (s, t, o = 0) => {
        try {
            const rT = s.getters['system/getRng']('treasureTier_' + t, o);
            const rG = s.getters['system/getRng']('treasure_' + t, o);
            const tC = s.getters['treasure/tierChancesRaw'];
            let tier = null, total = 0;
            const next = rT();
            tC.forEach(e => {
                total += e.chance;
                tier === null && next < total && (tier = e.tier);
            });

            if (!tier && tier !== 0) return null;

            let eL = {};
            const gE = s.state.treasure.effect, gU = s.state.unlock;

            for (const [k, e] of Object.entries(gE)) {
                if (k === 'mining' || gU[`${k}Feature`]?.see) {
                    for (const [sk, se] of Object.entries(e)) {
                        if (!se.unlock || gU[se.unlock]?.see) {
                            !eL[se.type] && (eL[se.type] = []);
                            eL[se.type].push(sk);
                        }
                    }
                }
            }
            let chosen = [];
            const cfg = s.state.treasure.type[t];

            cfg.slots.forEach(slot => {
                const arr = eL[slot.type];
                if (arr?.length) {
                    const idx = Math.floor(rG() * arr.length);
                    const elem = arr[idx];
                    eL[slot.type] = arr.filter(el => el !== elem);
                    chosen.push(elem);
                }
            });
            const vals = chosen.map((el, i) => {
                const feat = s.state.treasure.effectToFeature[el];
                const obj = s.state.treasure.effect[feat][el];
                return s.getters['treasure/effectValue'](obj.value * cfg.slots[i].power, tier, 0, t);
            });

            return { tier, type: t, effect: chosen, valueCache: vals };
        } catch (e) { return null; }
    };
    const decap = s => s.charAt(0).toLowerCase() + s.slice(1);
    const getName = (_, e) => {
        try {
            const v = document.getElementsByClassName("primary")[0]?.__vue__;
            if (!v?.$vuetify?.lang?.t) return e;
            const isGain = e.match(/currency(\w|-)+Gain/) && !e.match(/currency(\w|-)+CapGain/);
            const isCap = e.match(/currency(\w|-)+Cap/) && !e.match(/currency(\w|-)+Gain/);
            if (isGain) {
                let p = e.slice(8, -4).split(/(?=[A-Z])/);
                const f = decap(p[0]);
                p.splice(0, 1);
                const c = decap(p.join(''));
                const n = `${f}_${c}`;
                const t = v.$vuetify.lang.t(`$vuetify.currency.${n}.name`);
                if (t !== `$vuetify.currency.${n}.name`) return v.$vuetify.lang.t('$vuetify.gooboo.multGain', t);
            }
            if (isCap) {
                let p = e.slice(8, -3).split(/(?=[A-Z])/);
                const f = decap(p[0]);
                p.splice(0, 1);
                const c = decap(p.join(''));
                const n = `${f}_${c}`;
                const t = v.$vuetify.lang.t(`$vuetify.currency.${n}.name`);
                if (t !== `$vuetify.currency.${n}.name`) return v.$vuetify.lang.t('$vuetify.gooboo.multCapacity', t);
            }
            const k = `$vuetify.mult.${e}`;
            const t = v.$vuetify.lang.t(k);
            return t !== k ? t : e;
        } catch { return e; }
    };
    const format = (t, s) => {
        if (!t) return `<div style="color: #ff5252;">预测失败</div>`;
        const c = ['#ffffff', '#ffeb3b', '#ff9800', '#f44336', '#9c27b0'][t.tier] || '#ffffff';
        let txt = '';
        t.effect.forEach((e, i) => {
            const v = t.valueCache[i];
            const n = getName(s, e);
            if (i > 0) txt += ', ';
            txt += `${n} ×${(v + 1).toFixed(2)}`;
        });
        return `<div style="margin: 2px 0; font-size: 14px;"><span style="color: ${c};">${txt}</span></div>`;
    };
    const createTip = () => {
        const t = document.createElement('div');
        t.id = 'treasure-predictor-tooltip';
        t.style.cssText = `position:absolute;background:rgba(33,33,33,0.95);color:#fff;border:1px solid rgba(255,255,255,0.2);border-radius:4px;padding:8px 12px;font-family:Roboto,sans-serif;font-size:14px;line-height:1.4;z-index:10000;box-shadow:0 2px 8px rgba(0,0,0,0.3);max-width:400px;display:none;pointer-events:none`;
        t.innerHTML = `<div id="tooltip-prediction-results">加载中...</div>`;
        document.body.appendChild(t);
        return t;
    };
    const showTip = (e, c) => {
        const t = document.getElementById('treasure-predictor-tooltip');
        if (!t) return;
        t.querySelector('#tooltip-prediction-results').innerHTML = c;
        t.style.display = 'block';
        const r = e.target.getBoundingClientRect();
        const tr = t.getBoundingClientRect();
        let l = r.left + r.width + 10;
        let top = r.top;
        l + tr.width > window.innerWidth && (l = r.left - tr.width - 10);
        top + tr.height > window.innerHeight && (top = window.innerHeight - tr.height - 10);
        top < 0 && (top = 10);
        l < 0 && (l = 10);
        t.style.left = l + 'px';
        t.style.top = top + 'px';
    };
    const hideTip = () => {
        const t = document.getElementById('treasure-predictor-tooltip');
        t && (t.style.display = 'none');
    };
    const bind = s => {
        const btns = document.querySelectorAll('[data-cy="treasure-buy-regular"], [data-cy="treasure-buy-dual"], [data-cy="treasure-buy-empowered"], [data-cy="treasure-buy-ancient"]');
        btns.forEach(b => {
            const t = b.getAttribute('data-cy').replace('treasure-buy-', '');
            b.removeEventListener('mouseenter', b._tpEnter);
            b.removeEventListener('mouseleave', b._tpLeave);
            b._tpEnter = e => {
                if (!isTreasure(s)) return;
                let r = '';
                for (let i = 0; i < 10; i++) r += format(predict(s, t, i), s);
                showTip(e, r);
            };
            b._tpLeave = () => hideTip();
            b.addEventListener('mouseenter', b._tpEnter);
            b.addEventListener('mouseleave', b._tpLeave);
        });
    };
    const isTreasure = s => s.state.system.screen === 'treasure';
    (async () => {
        try {
            const s = await waitGame();
            createTip();
            const init = () => isTreasure(s) && setTimeout(() => bind(s), 500);
            init();
            let last = s.state.system.screen;
            setInterval(() => {
                const curr = s.state.system.screen;
                curr !== last && (last = curr, init());
            }, 500);
        } catch (e) { console.error('启动失败:', e); }
    })();

})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址