AQ Ruffle Enhance

Adds multi-windowed capability for serious AQ play.

当前为 2023-09-05 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         AQ Ruffle Enhance
// @namespace    http://tampermonkey.net/
// @version      0.4.4
// @description  Adds multi-windowed capability for serious AQ play.
// @author       You
// @match        https://*.battleon.com/game/web*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=battleon.com
// @grant        none
// @license      MIT
// ==/UserScript==

const gameSwf = document.getElementsByClassName("base")[0].src;
const baseSwf = window.location.origin + '/game/flash/';
const MAX_PLAYERS = 6;
const MENU_BAR_HEIGHT = 20;
const serverOptions = [
    { value: 'aq', name: 'aq' },
    { value: 'guardian', name: 'guardian' },
    { value: 'new', name: 'new' }
];

const links = [
    { url: 'https://account.battleon.com/', name: 'Manage Account' },
    { url: 'https://aq-char-info.firebaseapp.com/', name: 'Char Info' },
    { url: 'https://battleon.com/', name: 'Home' },
    { url: 'https://adventurequestwiki.fandom.com/wiki/AdventureQuestWiki_Wiki', name: 'Wiki' },
    { url: 'https://forums2.battleon.com/f/tt.asp?forumid=1', name: 'Forums' },
    { url: 'https://discord.com/invite/FQsFCGV', name: 'Discord' },
]

const resizeWindows = () => {
    const container = document.getElementById('container');
    container.style.width = window.innerWidth;
    const playerContainers = Array.from(document.getElementsByClassName('player-container'));

    if (playerContainers.length === 0) {
        addWindow();
        resizeWindows();
        return;
    }

    // Thanks to nivp for the window resize algorithm!
    const availableHeight = window.innerHeight - MENU_BAR_HEIGHT;
    let max_width = 0;
    let max_height = 0;

    // maximize cell size through column search
    for (let i = 1; i <= playerContainers.length; i++) {
        let temp_height = availableHeight / Math.ceil(playerContainers.length / i);
        let temp_width = temp_height * 4 / 3;
        if (temp_width * i > (window.innerWidth * i) / (i + 1) && temp_width * i <= window.innerWidth) {
            max_width = temp_width;
            max_height = temp_height;
        }
    }

    // maximize cell size through row search
    for (let i = 1; i <= playerContainers.length; i++) {
        let temp_width = window.innerWidth / Math.ceil(playerContainers.length / i);
        let temp_height = temp_width * 3 / 4;
        if (
            temp_height * i > (availableHeight * i) / (i + 1) &&
            temp_height * i <= availableHeight
        ) {
            max_width = temp_width;
            max_height = temp_height;
        }
    }

    playerContainers.forEach((player) => {
        player.style.width = max_width;
        player.style.height = max_height;

        const rufflePlayer = player.getElementsByTagName('ruffle-player')[0];
        const playerMenuBar = player.getElementsByClassName('player-menu-bar')[0];

        rufflePlayer.style.height = max_height;
        rufflePlayer.style.width = max_height * 4 / 3;
        playerMenuBar.style.width = max_height * 4 / 3;
    });
};

const addWindow = () => {
    const container = document.getElementById('container');
    const player = window.RufflePlayer.newest().createPlayer();
    const playerContainer = document.createElement('div');
    const playerMenuBar = document.createElement('div');
    playerMenuBar.className = 'player-menu-bar';

    playerContainer.className = 'player-container';
    playerContainer.style = 'display: flex; flex-direction: column; align-items: center;';
    playerMenuBar.style = `height: ${MENU_BAR_HEIGHT}px; background-color: grey; display: flex; justify-content: center;`;
    player.style = 'margin: 0 auto;';

    const killWindowButton = document.createElement('button');
    killWindowButton.innerText = 'x';
    killWindowButton.onclick = () => {
        playerContainer.remove();
        document.getElementById('add-button').disabled = false;
        document.getElementById('add-all-button').disabled = false;
        resizeWindows();
    };

    const refreshPlayerButton = document.createElement('button');
    refreshPlayerButton.innerText = 'Refresh Window';
    refreshPlayerButton.onclick = () => player.reload();

    playerContainer.appendChild(playerMenuBar);
    playerMenuBar.appendChild(refreshPlayerButton);
    playerMenuBar.appendChild(killWindowButton);
    playerContainer.appendChild(player);
    container.appendChild(playerContainer);

    player.load({
        url: gameSwf,
        base: baseSwf,
        preferredRenderer: "webgpu"
    });
};

const addAllWindows = () => {
    const playerContainers = document.getElementsByTagName('ruffle-player');
    for (let i = playerContainers.length; i < MAX_PLAYERS; i++) {
        addWindow();
    }
}

const renderMenuBar = () => {
    const menuBar = document.createElement('div');
    menuBar.style = `height: ${MENU_BAR_HEIGHT}px; width: 100%; display: flex; justify-content: space-between;`;

    const addButton = document.createElement("button");
    addButton.id = 'add-button';
    addButton.innerText = 'Add Window';

    addButton.onclick = () => {
        addWindow();
        const playerContainers = document.getElementsByTagName('ruffle-player');
        document.getElementById('add-button').disabled = playerContainers.length === MAX_PLAYERS;
        document.getElementById('add-all-button').disabled = playerContainers.length === MAX_PLAYERS;
        resizeWindows();
    };

    const addAllButton = document.createElement("button");
    addAllButton.id = 'add-all-button';
    addAllButton.innerText = 'Max Windows (6)';

    addAllButton.onclick = () => {
        addAllWindows();
        document.getElementById('add-button').disabled = true;
        addAllButton.disabled = true;
        resizeWindows();
    };

    const killAllButton = document.createElement('button');
    killAllButton.id = 'kill-all-button';
    killAllButton.innerText = 'Kill All Windows';
    killAllButton.onclick = () => {
        const playerContainers = Array.from(document.getElementsByClassName('player-container'));
        playerContainers.forEach((playerContainer) => {
            playerContainer.remove();
        });
        document.getElementById('add-button').disabled = false;
        document.getElementById('add-all-button').disabled = false;
        addWindow();
        resizeWindows();
    };

    const goToServer = document.createElement('button');
    goToServer.textContent = 'Open New Tab';
    goToServer.onclick = () => {
        const select = document.getElementById('server-select');
        window.open(`https://${select.value}.battleon.com/game/web`);
    };

    const dropdown = document.createElement('select');
    dropdown.id = 'server-select';
    serverOptions.forEach((serverOption) => {
        const option = document.createElement('option');
        option.value = serverOption.value;
        option.text = serverOption.name;
        dropdown.appendChild(option);
    });

    const buttonGroup = document.createElement('div');
    buttonGroup.appendChild(addButton);
    buttonGroup.appendChild(addAllButton);
    buttonGroup.appendChild(killAllButton);

    const linksGroup = document.createElement('div');
    links.forEach((link, index) => {
        const newLink = document.createElement('a');
        newLink.textContent = link.name;
        newLink.href = link.url;
        newLink.target = '_blank';
        newLink.rel = 'noopener';
        newLink.style = 'font-size: 16px;';
        linksGroup.appendChild(newLink);
        if (index !== links.length - 1) {
            const sep = document.createElement('span');
            sep.textContent = '|';
            sep.style = 'font-size: 16px; margin: 5px;';
            linksGroup.appendChild(sep);
        }
    })

    const selectGroup = document.createElement('div');
    selectGroup.appendChild(dropdown);
    selectGroup.appendChild(goToServer);


    menuBar.appendChild(buttonGroup);
    menuBar.appendChild(linksGroup);
    menuBar.appendChild(selectGroup);

    const playersGroup = document.createElement('div');
    playersGroup.id = "container";
    playersGroup.style = 'display: flex; flex-wrap: wrap; justify-content: center;';

    document.body.appendChild(playersGroup);
    playersGroup.appendChild(menuBar);
}

(function() {
    'use strict';
    let resizer = window.addEventListener('resize', () => {
        let timer;
        if (timer) {
            clearTimeout(timer);
        }
        timer = setTimeout(() => {
            resizeWindows();
        }, 250);
    });

    const checker = setInterval(() => {
        if (window.RufflePlayer && window.RufflePlayer.invoked) {
            clearInterval(checker);
            document.body.style.margin = 0;
            document.getElementById('main').remove();

            renderMenuBar();
            addWindow();
            resizeWindows();
        }
    }, 500);

    setTimeout(() => {
        clearInterval(checker);
    }, 2500);
})();