The West Perseus Toolkit

Useful tools for The West.

// ==UserScript==
// @name        The West Perseus Toolkit
// @author      Mr. Perseus
// @namespace   tw-perseus
// @description Useful tools for The West.
// @include     https://*.the-west.*/game.php*
// @include     http://*.the-west.*/game.php*
// @include     https://*.tw.innogames.*/game.php*
// @include     http://*.tw.innogames.*/game.php*
// @version     1.3.0
// @grant       none
// ==/UserScript==

(function(fn) {
    const script = document.createElement('script');
    script.setAttribute('type', 'application/javascript');
    script.textContent = `(${fn})();`;
    document.body.appendChild(script);
    document.body.removeChild(script);
})(() => {
    $(document).ready(() => {
        const TWPT = {
            base64: {
                menuImage:
                    "url('data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAASABIAAD/4QCMRXhpZgAATU0AKgAAAAgABQESAAMAAAABAAEAAAEaAAUAAAABAAAASgEbAAUAAAABAAAAUgEoAAMAAAABAAIAAIdpAAQAAAABAAAAWgAAAAAAAABIAAAAAQAAAEgAAAABAAOgAQADAAAAAQABAACgAgAEAAAAAQAAABmgAwAEAAAAAQAAABkAAAAA/+0AOFBob3Rvc2hvcCAzLjAAOEJJTQQEAAAAAAAAOEJJTQQlAAAAAAAQ1B2M2Y8AsgTpgAmY7PhCfv/AABEIABkAGQMBIgACEQEDEQH/xAAfAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgv/xAC1EAACAQMDAgQDBQUEBAAAAX0BAgMABBEFEiExQQYTUWEHInEUMoGRoQgjQrHBFVLR8CQzYnKCCQoWFxgZGiUmJygpKjQ1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4eLj5OXm5+jp6vHy8/T19vf4+fr/xAAfAQADAQEBAQEBAQEBAAAAAAAAAQIDBAUGBwgJCgv/xAC1EQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS8BVictEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2dri4+Tl5ufo6ery8/T19vf4+fr/2wBDAAUDBAQEAwUEBAQFBQUGBwwIBwcHBw8LCwkMEQ8SEhEPERETFhwXExQaFRERGCEYGh0dHx8fExciJCIeJBweHx7/2wBDAQUFBQcGBw4ICA4eFBEUHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh7/3QAEAAL/2gAMAwEAAhEDEQA/APHLTT9Z1bU7101HUApunA2t8qgHp0rqbXwHq0ttuOo6kGI67zXpX7PEA1bw5rGmGCF3S6llRmAGMOSQTjjI5r0iNLRtEvpBEgCNEA2QNoO7+eBXwmPzDFqs4wdld213sfQUIUlH3o3/AOCfJHjfw54i8PKsrajqSLhHG9iMgkeorpvt93/z9Tf9917h+0FdaMPAWvQ3yJNeyWkK2I8v5rVgvLFv4geDtFeBbx6frXuZZiJ1qT53do4qyXNeKsf/0PP/AIdePv8AhHW1TTGvmtop7lvMHK5AbPb612yfEjRfIZBfwFWxkZPOOmRXmV1/rR9Kb2r5fE5LSxE/aOTR7VLHSpR5eVMu/E74gx6zaPZ28jTGQqhbDEkZ6fhUGW/55tUEf+tH1FSV3YXDQwkOSBz1q0q0rs//2Q==')",
            },
            version: '1.3.0',
            settingsKey: 'TWPT_preferences',
            defaultPreferences: {
                CinemaSkipButton: true,
                ZoomMap: true,
                DisablePremiumNotifications: true,
                NineTimesFifteenButton: true,
                HideDrawingMap: true,
                ChatImprovements: true,
                AlwaysShowFortBattleRecruitment: true,
            },
            preferences: {},
            currentZoom: 1,
        };

        TWPT.Updater = {
            init() {
                setTimeout(TWPT.Updater.load, 5000);
            },

            load() {
                $.getScript(
                    'https://rawcdn.githack.com/mr-perseus/tw-js-library/master/script-updater.js',
                    () => {
                        if (scriptUpdater.TWPT > TWPT.version) {
                            const updateMessage = new west.gui.Dialog(
                                'Update: The West Perseus Toolkit',
                                `<span>Update Available<br><br><b>v${scriptUpdater.TWPT}:</b><br>${scriptUpdater.TWPTNew}</span>`,
                                west.gui.Dialog.SYS_WARNING,
                            )
                                .addButton('Update', () => {
                                    updateMessage.hide();
                                    window.location.href =
                                        'https://greasyfork.org/scripts/370137-the-west-perseus-toolkit/code/The%20West%20Perseus%20Toolkit.user.js';
                                })
                                .addButton('cancel')
                                .show();
                        }
                    },
                );
            },
        };

        TWPT.Settings = {
            init() {
                const storage = JSON.parse(
                    localStorage.getItem(TWPT.settingsKey),
                );
                TWPT.preferences = storage || TWPT.defaultPreferences;

                const div = $('<div class="ui_menucontainer" />');
                const link = $(
                    '<div id="TWPT_Menu" class="menulink" title="The West Perseus Toolkit" />',
                )
                    .css('background-image', TWPT.base64.menuImage)
                    .css('background-position', '0px 0px')
                    .mouseenter(function() {
                        $(this).css('background-position', '-2px 0px');
                    })
                    .mouseleave(function() {
                        $(this).css('background-position', '0px 0px');
                    });

                $(link).on('click', () => {
                    TWPT.Settings.refreshMenu();
                });

                $('#ui_menubar').append(
                    div
                        .append(link)
                        .append('<div class="menucontainer_bottom" />'),
                );
            },

            refreshMenu() {
                const win = wman
                    .open('TWPTSettings', 'TWPT Settings', 'noreload')
                    .setMaxSize(1268, 838)
                    .setMiniTitle('TWPT Settings');
                const scrollPane = new west.gui.Scrollpane();

                const setTitle = function(name) {
                    scrollPane.appendContent(
                        `<p><span style="font-size: 130%; font-weight: bold; font-style: italic; display: inline-block; margin-top: 20px;">${name}</span></p>`,
                    );
                };

                const setCheckBox = function(prefName, text) {
                    const checkbox = new west.gui.Checkbox(text);
                    checkbox.setId(`TWPT_${prefName}`);
                    if (TWPT.preferences[prefName]) {
                        checkbox.toggle();
                    }
                    checkbox.setCallback(() => {
                        TWPT.preferences[prefName] = checkbox.isSelected();
                        localStorage.setItem(
                            TWPT.settingsKey,
                            JSON.stringify(TWPT.preferences),
                        );
                        TWPT.Settings.refreshMenu();
                        new UserMessage(
                            'Okay. Please refresh your page.',
                            'success',
                        ).show();
                    });
                    scrollPane.appendContent(checkbox.getMainDiv());
                    scrollPane.appendContent('<br/>');
                };

                setTitle('Enabled Features');
                setCheckBox(
                    'CinemaSkipButton',
                    'Enable the Cinema Skip button (allows to skip cinema videos after 5 seconds).',
                );
                setCheckBox(
                    'ZoomMap',
                    'Enable the Zoom feature (hover the minimap icon on the top right and scroll up / down to zoom out / in).',
                );
                setCheckBox(
                    'DisablePremiumNotifications',
                    'Suppress energy refill and automation premium notifications.',
                );
                setCheckBox(
                    'NineTimesFifteenButton',
                    'Add a button to job windows which allows you to start 9x 15 second jobs at once.',
                );
                setCheckBox(
                    'HideDrawingMap',
                    'Hides "Drawing Map" flag which is buggy sometimes.',
                );
                setCheckBox(
                    'ChatImprovements',
                    'Enable Chat improvements: show online / idle status in Saloon chat.',
                );
                setCheckBox(
                    'AlwaysShowFortBattleRecruitment',
                    'Always show the recruitment button in fort battle windows. (even if you have no permissions)',
                );
                setTitle('Feedback');
                scrollPane.appendContent(
                    '<ul style="margin-left:15px;line-height:18px;">' +
                        '<li>Send a message to <a target="_blank" href="https://www.the-west.de/?ref=west_invite_linkrl&player_id=83071&world_id=1&hash=0dc5">Mr. Perseus on world DE1</a></li>' +
                        '<li>Contact me on <a target="_blank" href="https://greasyfork.org/forum/messages/add/Mr. Perseus">Greasy Fork</a></li>' +
                        '<li>Send me a message on the <a target="_blank" href="https://forum.beta.the-west.net/index.php?conversations/add&to=Mr.%20Perseus">The West Beta Forum</a> or the <a target="_blank" href="https://forum.the-west.de/index.php?conversations/add&to=Mr.%20Perseus">German The West Forum</a></li>' +
                        '</ul><br />Check out other scripts on <a target="_blank" href="https://greasyfork.org/de/users/179973-mr-perseus">Greasyfork</a>.',
                );

                setTitle(
                    'Import / Export settings from various userscripts (to clipboard)',
                );

                const exportButton = new west.gui.Button(
                    'Export settings',
                    () => {
                        const settings = {};

                        const settingsKeysToStore = [
                            'TWDW_preferences',
                            'TWPT_preferences',
                            'TWToolkit_preferences',
                            'TWCalc_Wardrobe',
                            'TWCalc_Settings',
                            'TWDS_h_',
                            'TWDS_settings',
                            'twir_features',
                        ];

                        Object.entries(localStorage).forEach(([key, value]) => {
                            if (
                                settingsKeysToStore.some((settingToStore) =>
                                    key.startsWith(settingToStore),
                                )
                            ) {
                                settings[key] = value;
                            }
                        });

                        console.log('exporting settings', settings);

                        navigator.clipboard
                            .writeText(JSON.stringify(settings))
                            .then(
                                () => {
                                    new UserMessage(
                                        'Successfully copied settings to clipboard. Please save it somewhere.',
                                        'success',
                                    ).show();
                                },
                                (error) => {
                                    console.error('TWPT error', error);
                                    new UserMessage(
                                        'Failed saving to clipboard. (see console for further details)',
                                        'error',
                                    ).show();
                                },
                            );
                    },
                );
                scrollPane.appendContent(exportButton.getMainDiv());

                scrollPane.appendContent(
                    '<div style="margin-left: 20px;display:inline-block">Enter here: <input id="TWPT_import"/></div>',
                );
                const importButton = new west.gui.Button(
                    'Import settings',
                    () => {
                        try {
                            const stringImport = $('#TWPT_import').val();

                            const settings = JSON.parse(stringImport);

                            Object.entries(settings).forEach(([key, value]) => {
                                console.log(`Importing ${key} = ${value}`);
                                localStorage[key] = value;
                            });

                            new UserMessage(
                                'Successfully imported settings.',
                                'success',
                            ).show();
                        } catch (error) {
                            console.error('TWPT error', error);
                            new UserMessage(
                                'Failed saving to clipboard. (see console for further details)',
                                'error',
                            ).show();
                        }
                    },
                );
                scrollPane.appendContent(importButton.getMainDiv());

                win.appendToContentPane(scrollPane.getMainDiv());
            },
        };

        TWPT.CinemaSkipButton = {
            init() {
                const button = new west.gui.Button('Skip ad', () => {
                    CinemaWindow.controller('rewards');
                });

                CinemaWindow.backup_twpt_cotroller = CinemaWindow.controller;
                CinemaWindow.controller = function(key) {
                    button.setVisible(false);
                    button.disable();

                    // Uncomment the following line if you want to access rewards directly.
                    // if (key === "video") return CinemaWindow.backup_twpt_cotroller("rewards");

                    if (key === 'video') {
                        let count = 15;
                        const countDown = () => {
                            if (count > 0) {
                                button.setCaption(`Skip ad (${count})`);
                                setTimeout(countDown, 1000);
                                count -= 1;
                            } else {
                                button.setCaption('Skip ad');
                                button.enable();
                            }
                        };
                        button.setVisible(true);
                        countDown();
                    }

                    // If there is no ad available you should be able to get the rewards.
                    if (key === 'noVideo') {
                        return CinemaWindow.backup_twpt_cotroller('rewards');
                    }

                    return CinemaWindow.backup_twpt_cotroller(key);
                };

                CinemaWindow.backup_twpt_open = CinemaWindow.open;
                CinemaWindow.open = function(townId) {
                    CinemaWindow.backup_twpt_open(townId);
                    const header = $(this.window.divMain).find(
                        '.tw2gui_inner_window_title',
                    );
                    button.divMain.setAttribute(
                        'style',
                        'margin-left: 20px; margin-top: -20px; position: absolute',
                    );
                    button.divMain.lastChild.setAttribute(
                        'style',
                        'line-height: normal; padding-top: 10px;',
                    );
                    button.setVisible(false);
                    header.append(button.getMainDiv());
                };
            },
        };

        TWPT.ZoomMap = {
            init() {
                $(window).bind('mousewheel', (event) => {
                    if ($('#ui_minimap').is(':hover')) {
                        if (event.originalEvent.wheelDelta >= 0) {
                            if (TWPT.currentZoom < 1.95)
                                TWPT.currentZoom += 0.1;
                        } else if (TWPT.currentZoom > 0.75)
                            TWPT.currentZoom -= 0.1;

                        document.getElementById('map').style.zoom =
                            TWPT.currentZoom;
                    }
                });
            },
        };

        TWPT.DisablePremiumNotifications = {
            init() {
                Premium.checkForEnergyPremium = function(
                    callback,
                    failCallback,
                ) {
                    if (typeof failCallback !== 'undefined')
                        return failCallback();

                    return () => {};
                };
                Premium.checkForAutomationPremium = function(
                    callback,
                    failCallback,
                ) {
                    if (typeof failCallback !== 'undefined')
                        return failCallback();

                    return () => {};
                };
            },
        };

        TWPT.NineTimesFifteenButton = {
            init() {
                JobWindow.backup_twpt_initView = JobWindow.initView;
                JobWindow.initView = function() {
                    JobWindow.backup_twpt_initView.apply(this, arguments);
                    const button = new west.gui.Button('9x 15s', () => {
                        button.disable();
                        const jobAmountNum = this.window.divMain.getElementsByClassName(
                            'job-amount-num',
                        )[0];
                        const numberBefore = jobAmountNum.innerHTML;
                        jobAmountNum.innerHTML = '9';
                        $(this.window.divMain)
                            .find('.job_durationbar.job_durationbar_short')
                            .click();
                        setTimeout(() => {
                            button.enable();
                            jobAmountNum.innerHTML = numberBefore;
                        }, 5000);
                    });

                    const buttonDiv = button.getMainDiv();
                    buttonDiv.style['z-index'] = '5';
                    buttonDiv.style.bottom = '25px';
                    buttonDiv.style.left = '300px';
                    this.window.divMain
                        .querySelector('div.tw2gui_window_content_pane')
                        .appendChild(button.getMainDiv());
                };
            },
        };

        TWPT.HideDrawingMap = {
            init() {
                GameLoader.backup_twpt_async = GameLoader.async;
                GameLoader.async = function(message, signal, callback, max) {
                    GameLoader.backup_twpt_async(
                        message,
                        signal,
                        callback,
                        max,
                        true,
                        true,
                    );
                };
            },
        };

        TWPT.ChatImprovements = {
            init() {
                Chat.Resource.Client.prototype.isStranger = function() {
                    return false;
                };
            },
        };

        TWPT.AlwaysShowFortBattleRecruitment = {
            init() {
                FortBattleWindow.backup_twpt_getInfoArea =
                    FortBattleWindow.backup_twpt_getInfoArea ||
                    FortBattleWindow.getInfoArea;
                FortBattleWindow.getInfoArea = function() {
                    this.preBattle.battleData.canSetPrivilege = true;
                    return FortBattleWindow.backup_twpt_getInfoArea.apply(
                        this,
                        arguments,
                    );
                };
            },
        };

        try {
            TWPT.Updater.init();
            TWPT.Settings.init();
            Object.keys(TWPT.preferences).forEach((property) => {
                if (TWPT.preferences[property]) {
                    try {
                        TWPT[property].init();
                    } catch (err) {
                        console.error(
                            `TWPT Error with feature "${property}".`,
                            err,
                        );
                    }
                }
            });
        } catch (err) {
            console.error('TWPT ERROR', err);
        }
    });
});