Ultra+ Timer

made with much love

  1. // ==UserScript==
  2. // @name Ultra+ Timer
  3. // @description made with much love
  4. // @version 0.0.5
  5. // @author Cazka#1820
  6. // @match *://florr.io/*
  7. // @license MIT
  8. // @namespace https://greasyfork.org/users/541070
  9. // @grant GM_setValue
  10. // @grant GM_getValue
  11. // @grant GM_registerMenuCommand
  12. // @run-at document-end
  13. // ==/UserScript==
  14.  
  15. const bosses = [
  16. {
  17. name: 'Beetle',
  18. set spawnedAt(v) {
  19. GM_setValue(this.name, v);
  20. },
  21. get spawnedAt() {
  22. return GM_getValue(this.name, null);
  23. },
  24. },
  25. {
  26. name: 'Bubble',
  27. set spawnedAt(v) {
  28. GM_setValue(this.name, v);
  29. },
  30. get spawnedAt() {
  31. return GM_getValue(this.name, null);
  32. },
  33. },
  34. {
  35. name: 'Cactus',
  36. set spawnedAt(v) {
  37. GM_setValue(this.name, v);
  38. },
  39. get spawnedAt() {
  40. return GM_getValue(this.name, null);
  41. },
  42. },
  43. {
  44. name: 'Centipede',
  45. set spawnedAt(v) {
  46. GM_setValue(this.name, v);
  47. },
  48. get spawnedAt() {
  49. return GM_getValue(this.name, null);
  50. },
  51. },
  52. {
  53. name: 'Cockroach',
  54. set spawnedAt(v) {
  55. GM_setValue(this.name, v);
  56. },
  57. get spawnedAt() {
  58. return GM_getValue(this.name, null);
  59. },
  60. },
  61. {
  62. name: 'Crab',
  63. set spawnedAt(v) {
  64. GM_setValue(this.name, v);
  65. },
  66. get spawnedAt() {
  67. return GM_getValue(this.name, null);
  68. },
  69. },
  70. {
  71. name: 'Fly',
  72. set spawnedAt(v) {
  73. GM_setValue(this.name, v);
  74. },
  75. get spawnedAt() {
  76. return GM_getValue(this.name, null);
  77. },
  78. },
  79. {
  80. name: 'Hornet',
  81. set spawnedAt(v) {
  82. GM_setValue(this.name, v);
  83. },
  84. get spawnedAt() {
  85. return GM_getValue(this.name, null);
  86. },
  87. },
  88. {
  89. name: 'Jellyfish',
  90. set spawnedAt(v) {
  91. GM_setValue(this.name, v);
  92. },
  93. get spawnedAt() {
  94. return GM_getValue(this.name, null);
  95. },
  96. },
  97. {
  98. name: 'Leech',
  99. set spawnedAt(v) {
  100. GM_setValue(this.name, v);
  101. },
  102. get spawnedAt() {
  103. return GM_getValue(this.name, null);
  104. },
  105. },
  106. {
  107. name: 'Moth',
  108. set spawnedAt(v) {
  109. GM_setValue(this.name, v);
  110. },
  111. get spawnedAt() {
  112. return GM_getValue(this.name, null);
  113. },
  114. },
  115. {
  116. name: 'Queen Ant',
  117. set spawnedAt(v) {
  118. GM_setValue(this.name, v);
  119. },
  120. get spawnedAt() {
  121. return GM_getValue(this.name, null);
  122. },
  123. },
  124. {
  125. name: 'Queen Fire Ant',
  126. set spawnedAt(v) {
  127. GM_setValue(this.name, v);
  128. },
  129. get spawnedAt() {
  130. return GM_getValue(this.name, null);
  131. },
  132. },
  133. {
  134. name: 'Rock',
  135. set spawnedAt(v) {
  136. GM_setValue(this.name, v);
  137. },
  138. get spawnedAt() {
  139. return GM_getValue(this.name, null);
  140. },
  141. },
  142. {
  143. name: 'Sandstorm',
  144. set spawnedAt(v) {
  145. GM_setValue(this.name, v);
  146. },
  147. get spawnedAt() {
  148. return GM_getValue(this.name, null);
  149. },
  150. },
  151. {
  152. name: 'Shell',
  153. set spawnedAt(v) {
  154. GM_setValue(this.name, v);
  155. },
  156. get spawnedAt() {
  157. return GM_getValue(this.name, null);
  158. },
  159. },
  160. {
  161. name: 'Spider',
  162. set spawnedAt(v) {
  163. GM_setValue(this.name, v);
  164. },
  165. get spawnedAt() {
  166. return GM_getValue(this.name, null);
  167. },
  168. },
  169. ];
  170.  
  171. const menu = document.body.appendChild(document.createElement('div'));
  172. menu.style.padding = '15px';
  173. menu.style.background = '#ffffff3f';
  174. menu.style['border-radius'] = '10px';
  175. menu.style.display = GM_getValue('menuDisplay', 'block');
  176. menu.style.position = 'absolute';
  177. menu.style['pointer-events'] = 'none';
  178. menu.style.bottom = '5px';
  179. menu.style.right = '5px';
  180.  
  181. const table = menu.appendChild(document.createElement('table'));
  182. table.style['font-family'] = 'Ubuntu';
  183. table.style['border-collapse'] = 'collapse';
  184. table.style.width = `100%`;
  185.  
  186. updateTable();
  187. setInterval(updateTable, 5000);
  188.  
  189. // Tampermonkey menu
  190. GM_registerMenuCommand('Toggle Menu', (event) => {
  191. const newValue = GM_getValue('menuDisplay', 'block') == 'block' ? 'none' : 'block';
  192. GM_setValue('menuDisplay', newValue);
  193. menu.style.display = newValue;
  194. });
  195.  
  196. // functions
  197. function updateTable() {
  198. while (table.rows.length > 0) {
  199. table.deleteRow(0);
  200. }
  201.  
  202. bosses.sort((a, b) => {
  203. if (a.spawnedAt == null && b.spawnedAt == null) {
  204. return a.name.localeCompare(b.name);
  205. }
  206.  
  207. return (a.spawnedAt ?? Infinity) - (b.spawnedAt ?? Infinity);
  208. });
  209. bosses.forEach((x) => {
  210. const minutes = Math.floor((Date.now() - x.spawnedAt) / 1000 / 60);
  211. if (minutes > 240) {
  212. x.spawnedAt = null;
  213. }
  214. });
  215. bosses.forEach((x, i) => {
  216. const tr = table.insertRow();
  217.  
  218. // Mob
  219. const td1 = tr.insertCell();
  220. if (i !== 0) {
  221. td1.style['padding-top'] = '5px';
  222. }
  223. if (i !== bosses.length - 1) {
  224. td1.style['padding-bottom'] = '5px';
  225. }
  226. td1.style['padding-right'] = '20px';
  227.  
  228. td1.appendChild(document.createTextNode(x.name));
  229.  
  230. // minutes ago
  231. const td2 = tr.insertCell();
  232. if (i !== 0) {
  233. td2.style['padding-top'] = '5px';
  234. }
  235. if (i !== bosses.length - 1) {
  236. td2.style['padding-bottom'] = '5px';
  237. }
  238. td2.style['pointer-events'] = 'auto';
  239. td2.style.cursor = 'pointer';
  240.  
  241. td2.appendChild(document.createTextNode(toTimeSpanString(x.spawnedAt)));
  242.  
  243. td2.onclick = (e) => {
  244. if (e.shiftKey) {
  245. const input = window.prompt(`Manually set the timer of ${x.name}`);
  246. if (isNaN(input)) {
  247. return;
  248. }
  249.  
  250. x.spawnedAt = Date.now() - input * 60 * 1000;
  251.  
  252. updateTable();
  253. return;
  254. }
  255. if (!window.confirm(`Do you really want to reset the timer of ${x.name}?`)) {
  256. return;
  257. }
  258. x.spawnedAt = Date.now();
  259. updateTable();
  260. };
  261. td2.addEventListener('contextmenu', (e) => e.preventDefault());
  262. });
  263. }
  264. function toTimeSpanString(timestamp) {
  265. if (timestamp == null) {
  266. return 'N/A';
  267. }
  268.  
  269. const minutes = Math.floor((Date.now() - timestamp) / 1000 / 60);
  270.  
  271. return `${minutes} minute${minutes !== 1 ? 's' : ''} ago`;
  272. }