AQ Ruffle Enhance

Adds multi-windowed capability for serious AQ play.

目前为 2023-09-05 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name AQ Ruffle Enhance
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.4.4
  5. // @description Adds multi-windowed capability for serious AQ play.
  6. // @author You
  7. // @match https://*.battleon.com/game/web*
  8. // @icon https://www.google.com/s2/favicons?sz=64&domain=battleon.com
  9. // @grant none
  10. // @license MIT
  11. // ==/UserScript==
  12.  
  13. const gameSwf = document.getElementsByClassName("base")[0].src;
  14. const baseSwf = window.location.origin + '/game/flash/';
  15. const MAX_PLAYERS = 6;
  16. const MENU_BAR_HEIGHT = 20;
  17. const serverOptions = [
  18. { value: 'aq', name: 'aq' },
  19. { value: 'guardian', name: 'guardian' },
  20. { value: 'new', name: 'new' }
  21. ];
  22.  
  23. const links = [
  24. { url: 'https://account.battleon.com/', name: 'Manage Account' },
  25. { url: 'https://aq-char-info.firebaseapp.com/', name: 'Char Info' },
  26. { url: 'https://battleon.com/', name: 'Home' },
  27. { url: 'https://adventurequestwiki.fandom.com/wiki/AdventureQuestWiki_Wiki', name: 'Wiki' },
  28. { url: 'https://forums2.battleon.com/f/tt.asp?forumid=1', name: 'Forums' },
  29. { url: 'https://discord.com/invite/FQsFCGV', name: 'Discord' },
  30. ]
  31.  
  32. const resizeWindows = () => {
  33. const container = document.getElementById('container');
  34. container.style.width = window.innerWidth;
  35. const playerContainers = Array.from(document.getElementsByClassName('player-container'));
  36.  
  37. if (playerContainers.length === 0) {
  38. addWindow();
  39. resizeWindows();
  40. return;
  41. }
  42.  
  43. // Thanks to nivp for the window resize algorithm!
  44. const availableHeight = window.innerHeight - MENU_BAR_HEIGHT;
  45. let max_width = 0;
  46. let max_height = 0;
  47.  
  48. // maximize cell size through column search
  49. for (let i = 1; i <= playerContainers.length; i++) {
  50. let temp_height = availableHeight / Math.ceil(playerContainers.length / i);
  51. let temp_width = temp_height * 4 / 3;
  52. if (temp_width * i > (window.innerWidth * i) / (i + 1) && temp_width * i <= window.innerWidth) {
  53. max_width = temp_width;
  54. max_height = temp_height;
  55. }
  56. }
  57.  
  58. // maximize cell size through row search
  59. for (let i = 1; i <= playerContainers.length; i++) {
  60. let temp_width = window.innerWidth / Math.ceil(playerContainers.length / i);
  61. let temp_height = temp_width * 3 / 4;
  62. if (
  63. temp_height * i > (availableHeight * i) / (i + 1) &&
  64. temp_height * i <= availableHeight
  65. ) {
  66. max_width = temp_width;
  67. max_height = temp_height;
  68. }
  69. }
  70.  
  71. playerContainers.forEach((player) => {
  72. player.style.width = max_width;
  73. player.style.height = max_height;
  74.  
  75. const rufflePlayer = player.getElementsByTagName('ruffle-player')[0];
  76. const playerMenuBar = player.getElementsByClassName('player-menu-bar')[0];
  77.  
  78. rufflePlayer.style.height = max_height;
  79. rufflePlayer.style.width = max_height * 4 / 3;
  80. playerMenuBar.style.width = max_height * 4 / 3;
  81. });
  82. };
  83.  
  84. const addWindow = () => {
  85. const container = document.getElementById('container');
  86. const player = window.RufflePlayer.newest().createPlayer();
  87. const playerContainer = document.createElement('div');
  88. const playerMenuBar = document.createElement('div');
  89. playerMenuBar.className = 'player-menu-bar';
  90.  
  91. playerContainer.className = 'player-container';
  92. playerContainer.style = 'display: flex; flex-direction: column; align-items: center;';
  93. playerMenuBar.style = `height: ${MENU_BAR_HEIGHT}px; background-color: grey; display: flex; justify-content: center;`;
  94. player.style = 'margin: 0 auto;';
  95.  
  96. const killWindowButton = document.createElement('button');
  97. killWindowButton.innerText = 'x';
  98. killWindowButton.onclick = () => {
  99. playerContainer.remove();
  100. document.getElementById('add-button').disabled = false;
  101. document.getElementById('add-all-button').disabled = false;
  102. resizeWindows();
  103. };
  104.  
  105. const refreshPlayerButton = document.createElement('button');
  106. refreshPlayerButton.innerText = 'Refresh Window';
  107. refreshPlayerButton.onclick = () => player.reload();
  108.  
  109. playerContainer.appendChild(playerMenuBar);
  110. playerMenuBar.appendChild(refreshPlayerButton);
  111. playerMenuBar.appendChild(killWindowButton);
  112. playerContainer.appendChild(player);
  113. container.appendChild(playerContainer);
  114.  
  115. player.load({
  116. url: gameSwf,
  117. base: baseSwf,
  118. preferredRenderer: "webgpu"
  119. });
  120. };
  121.  
  122. const addAllWindows = () => {
  123. const playerContainers = document.getElementsByTagName('ruffle-player');
  124. for (let i = playerContainers.length; i < MAX_PLAYERS; i++) {
  125. addWindow();
  126. }
  127. }
  128.  
  129. const renderMenuBar = () => {
  130. const menuBar = document.createElement('div');
  131. menuBar.style = `height: ${MENU_BAR_HEIGHT}px; width: 100%; display: flex; justify-content: space-between;`;
  132.  
  133. const addButton = document.createElement("button");
  134. addButton.id = 'add-button';
  135. addButton.innerText = 'Add Window';
  136.  
  137. addButton.onclick = () => {
  138. addWindow();
  139. const playerContainers = document.getElementsByTagName('ruffle-player');
  140. document.getElementById('add-button').disabled = playerContainers.length === MAX_PLAYERS;
  141. document.getElementById('add-all-button').disabled = playerContainers.length === MAX_PLAYERS;
  142. resizeWindows();
  143. };
  144.  
  145. const addAllButton = document.createElement("button");
  146. addAllButton.id = 'add-all-button';
  147. addAllButton.innerText = 'Max Windows (6)';
  148.  
  149. addAllButton.onclick = () => {
  150. addAllWindows();
  151. document.getElementById('add-button').disabled = true;
  152. addAllButton.disabled = true;
  153. resizeWindows();
  154. };
  155.  
  156. const killAllButton = document.createElement('button');
  157. killAllButton.id = 'kill-all-button';
  158. killAllButton.innerText = 'Kill All Windows';
  159. killAllButton.onclick = () => {
  160. const playerContainers = Array.from(document.getElementsByClassName('player-container'));
  161. playerContainers.forEach((playerContainer) => {
  162. playerContainer.remove();
  163. });
  164. document.getElementById('add-button').disabled = false;
  165. document.getElementById('add-all-button').disabled = false;
  166. addWindow();
  167. resizeWindows();
  168. };
  169.  
  170. const goToServer = document.createElement('button');
  171. goToServer.textContent = 'Open New Tab';
  172. goToServer.onclick = () => {
  173. const select = document.getElementById('server-select');
  174. window.open(`https://${select.value}.battleon.com/game/web`);
  175. };
  176.  
  177. const dropdown = document.createElement('select');
  178. dropdown.id = 'server-select';
  179. serverOptions.forEach((serverOption) => {
  180. const option = document.createElement('option');
  181. option.value = serverOption.value;
  182. option.text = serverOption.name;
  183. dropdown.appendChild(option);
  184. });
  185.  
  186. const buttonGroup = document.createElement('div');
  187. buttonGroup.appendChild(addButton);
  188. buttonGroup.appendChild(addAllButton);
  189. buttonGroup.appendChild(killAllButton);
  190.  
  191. const linksGroup = document.createElement('div');
  192. links.forEach((link, index) => {
  193. const newLink = document.createElement('a');
  194. newLink.textContent = link.name;
  195. newLink.href = link.url;
  196. newLink.target = '_blank';
  197. newLink.rel = 'noopener';
  198. newLink.style = 'font-size: 16px;';
  199. linksGroup.appendChild(newLink);
  200. if (index !== links.length - 1) {
  201. const sep = document.createElement('span');
  202. sep.textContent = '|';
  203. sep.style = 'font-size: 16px; margin: 5px;';
  204. linksGroup.appendChild(sep);
  205. }
  206. })
  207.  
  208. const selectGroup = document.createElement('div');
  209. selectGroup.appendChild(dropdown);
  210. selectGroup.appendChild(goToServer);
  211.  
  212.  
  213. menuBar.appendChild(buttonGroup);
  214. menuBar.appendChild(linksGroup);
  215. menuBar.appendChild(selectGroup);
  216.  
  217. const playersGroup = document.createElement('div');
  218. playersGroup.id = "container";
  219. playersGroup.style = 'display: flex; flex-wrap: wrap; justify-content: center;';
  220.  
  221. document.body.appendChild(playersGroup);
  222. playersGroup.appendChild(menuBar);
  223. }
  224.  
  225. (function() {
  226. 'use strict';
  227. let resizer = window.addEventListener('resize', () => {
  228. let timer;
  229. if (timer) {
  230. clearTimeout(timer);
  231. }
  232. timer = setTimeout(() => {
  233. resizeWindows();
  234. }, 250);
  235. });
  236.  
  237. const checker = setInterval(() => {
  238. if (window.RufflePlayer && window.RufflePlayer.invoked) {
  239. clearInterval(checker);
  240. document.body.style.margin = 0;
  241. document.getElementById('main').remove();
  242.  
  243. renderMenuBar();
  244. addWindow();
  245. resizeWindows();
  246. }
  247. }, 500);
  248.  
  249. setTimeout(() => {
  250. clearInterval(checker);
  251. }, 2500);
  252. })();