Kittens Game - Progress Bars

Adds progress bars to Kittens Game to see how close you are to an upgrade

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

ستحتاج إلى تثبيت إضافة مثل Stylus لتثبيت هذا النمط.

ستحتاج إلى تثبيت إضافة لإدارة أنماط المستخدم لتتمكن من تثبيت هذا النمط.

ستحتاج إلى تثبيت إضافة لإدارة أنماط المستخدم لتثبيت هذا النمط.

ستحتاج إلى تثبيت إضافة لإدارة أنماط المستخدم لتثبيت هذا النمط.

(لدي بالفعل مثبت أنماط للمستخدم، دعني أقم بتثبيته!)

// ==UserScript==
// @name         Kittens Game - Progress Bars
// @namespace    https://greasyfork.org/en/scripts/526715-kittens-game-progress-bars
// @version      1.3
// @description  Adds progress bars to Kittens Game to see how close you are to an upgrade
// @author       Mashiro-chan
// @match        https://kittensgame.com/web/
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    const init = () => {
        if (!game.resPool) {
            setTimeout(init, 100);
            return;
        }

        document.addEventListener("click", function(event) {
            const button = event.target.closest(".tab");
            if (button && !button.classList.contains("activeTab")) {
                updateButtons();
            }
        });

        var getButtons = () => {
            var buttons = [game.tabs.find(t => t.tabId == game.ui.activeTabId)]
                .flatMap(t => [...new Set(Object.keys(t).filter(k => /btn|button|panel|children/i.test(k)).flatMap(k => t[k]))])
                .filter(Boolean);
            while (buttons.some(x => !x.model)) {
                buttons = buttons.flatMap(x =>
                                          x.model
                                          ? x
                                          : [x.tradeBtn, x.race, x.embassyButton, x.children].flat().filter(Boolean)
                                         );
            }
            return buttons;
        };

        const extendPrices = prices => prices.map(p => ({
            'name': p.name,
            'have': game.resPool.get(p.name).value,
            'need': p.val
        })).map(p => ({
            ...p,
            'delta': p.need - p.have,
            'percent': p.have / p.need
        }));

        let progressBarColor = '#FF0000';

        const bodyClass = document.body.className.match(/scheme_([\w-]+)/);
        const themeName = bodyClass[1];
        const themeStylesheet = `theme_${themeName}.css`;
        const selector = `.scheme_${themeName} .btn.modern.disabled.limited span.btnTitle`;
        const sheet = [...document.styleSheets].find(s => s.href && s.href.includes(themeStylesheet));
        const rule = [...sheet.cssRules].find(r => r.selectorText === selector);

        progressBarColor = rule.style.color;

        const initButtonExtension = button => {
            const buttonContent = button.buttonContent;
            if (!buttonContent) return;

            const statusBar = document.createElement('div');
            statusBar.className = 'statusBar';
            Object.assign(statusBar.style, {
                display: 'none',
                position: 'absolute',
                bottom: '0px',
                left: '4%',
                height: '1px',
                width: '92%',
                pointerEvents: 'none'
            });
            buttonContent.appendChild(statusBar);
            button.statusBar = statusBar;

            const progressBar = document.createElement('div');
            progressBar.className = 'progressBar';
            Object.assign(progressBar.style, {
                display: 'inline-block',
                float: 'left',
                height: '100%',
                width: '0%',
                backgroundColor: progressBarColor,
                borderRadius: '2px 2px 2px 2px'
            });
            statusBar.appendChild(progressBar);
            statusBar.progressBar = progressBar;
        };

        const updateButtons = () => {
            document.querySelectorAll('.tabInner .btn.nosel .statusBar').forEach(el => {
                el.style.display = 'none';
            });

            getButtons()
                .filter(b => b.model.visible && !b.model.enabled && b.buttonContent.offsetParent)
                .filter(b => !/\((?:complete|in progress)\)/i.test(b.model.name))
                .forEach(button => {
                    if (!button.buttonContent.querySelector('.statusBar')) {
                        initButtonExtension(button);
                    }

                    const prices = extendPrices(button.model.prices);
                    const minPercent = Math.max(Math.min(1, ...prices.map(p => p.percent)), 0.01);
                    if (minPercent >= 1) return;

                    button.statusBar.style.display = 'inline-block';
                    button.statusBar.progressBar.style.width = (minPercent * 100) + '%';
                });
        };

        setInterval(() => {
            updateButtons();
        }, 100);
    };

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }
})();