Gartic IO Word Collector with Auto Skip

Collects words presented during the game, saves them to a file, and auto-skips

目前为 2025-03-07 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name Gartic IO Word Collector with Auto Skip
  3. // @namespace http://tampermonkey.net/
  4. // @version 2025-03-06
  5. // @description Collects words presented during the game, saves them to a file, and auto-skips
  6. // @author anonimbiri
  7. // @license MIT
  8. // @match https://gartic.io/*
  9. // @icon https://www.google.com/s2/favicons?sz=64&domain=gartic.io
  10. // @run-at document-start
  11. // @grant none
  12. // ==/UserScript==
  13.  
  14. (function() {
  15. 'use strict';
  16.  
  17. // Modify appendChild to intercept and alter the game's script
  18. Node.prototype.appendChild = new Proxy(Node.prototype.appendChild, {
  19. apply: function(target, thisArg, argumentsList) {
  20. const node = argumentsList[0];
  21. if (node.nodeName.toLowerCase() === 'script' && node.src && node.src.includes('room')) {
  22. console.log('Hedef script algılandı:', node.src);
  23. fetch(node.src)
  24. .then(response => response.text())
  25. .then(scriptContent => {
  26. let modifiedContent = scriptContent
  27. .replace(
  28. 'r.created||c?Rt("input",{type:"text",name:"chat",className:"mousetrap",autoComplete:"off",autoCorrect:"off",autoCapitalize:"off",value:i,placeholder:this._lang.chatHere,maxLength:100,enterKeyHint:"send",onChange:this.handleText,ref:this._ref}):Rt("input",{type:"text",name:"chat",className:"mousetrap",autoComplete:"off",autoCorrect:"off",autoCapitalize:"off",value:this._lang.loginChat,maxLength:100,ref:this._ref,disabled:!0})',
  29. 'Rt("input",{type:"text",name:"chat",className:"mousetrap",autoComplete:"off",autoCorrect:"off",autoCapitalize:"off",value:i,placeholder:this._lang.chatHere,maxLength:100,enterKeyHint:"send",onChange:this.handleText,ref:this._ref})'
  30. )
  31. .replace(
  32. 'this._timerAtivo=setInterval((function(){Date.now()-e._ativo>15e4&&(O(Object(f.a)(n.prototype),"emit",e).call(e,"avisoInativo"),e._ativo=Date.now())}),1e3)',
  33. 'this._timerAtivo=setInterval((function(){Date.now()-e._ativo>15e4&&e.active()}),1e3)'
  34. )
  35. .replace(
  36. 'e.unlock()}',
  37. 'e.unlock();window.game=e;setInterval(()=>{window.game=e},1000);}'
  38. );
  39. let blob = new Blob([modifiedContent], { type: 'application/javascript' });
  40. let blobUrl = URL.createObjectURL(blob);
  41. node.src = blobUrl;
  42. node.textContent = '';
  43. return target.apply(thisArg, [node]);
  44. })
  45. .catch(error => {
  46. console.error('Failed to fetch/modify script:', error);
  47. return target.apply(thisArg, argumentsList);
  48. });
  49. return node;
  50. }
  51. return target.apply(thisArg, argumentsList);
  52. }
  53. });
  54.  
  55. // Define wordList globally on window object
  56. window.wordList = {
  57. "custom": [],
  58. "General (en)": [],
  59. "General (tr)": [],
  60. "Anime (en)": []
  61. };
  62.  
  63. // Function to save wordList to a file
  64. function saveWordListToFile() {
  65. const theme = window.game && window.game._dadosSala && window.game._dadosSala.tema ? window.game._dadosSala.tema : "custom";
  66. const words = window.wordList[theme].join('\n');
  67. const blob = new Blob([words], { type: 'text/plain;charset=utf-8' });
  68. const url = URL.createObjectURL(blob);
  69. const link = document.createElement('a');
  70. link.href = url;
  71. link.download = `${theme}_words.txt`;
  72. document.body.appendChild(link);
  73. link.click();
  74. document.body.removeChild(link);
  75. URL.revokeObjectURL(url);
  76. }
  77.  
  78. // Inject UI for the word collector (right side, vertical)
  79. const collectorHTML = `
  80. <div id="wordCollector" style="position: fixed; top: 20px; right: 20px; width: 200px; background: rgba(30, 30, 47, 0.9); padding: 15px; border-radius: 8px; color: #fff; z-index: 1000; display: flex; flex-direction: column; gap: 10px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);">
  81. <h3 style="margin: 0; color: #ff69b4; font-size: 16px; text-align: center;">Word Collector</h3>
  82. <p style="margin: 0; font-size: 12px; text-align: center;">Collects words and skips turn</p>
  83. <button id="saveWordsBtn" style="background: #ff69b4; border: none; padding: 8px; border-radius: 5px; color: #1e1e2f; cursor: pointer; font-size: 14px;">Save Words</button>
  84. <label for="importWords" style="background: #a5e2fe; border: none; padding: 8px; border-radius: 5px; color: #1e1e2f; cursor: pointer; font-size: 14px; text-align: center;">Import Words</label>
  85. <input type="file" id="importWords" accept=".txt" style="display: none;">
  86. <div id="wordCount" style="font-size: 12px; text-align: center;"></div>
  87. </div>
  88. `;
  89. document.body.insertAdjacentHTML('beforeend', collectorHTML);
  90.  
  91. // Update word count display
  92. function updateWordCount() {
  93. const theme = window.game && window.game._dadosSala && window.game._dadosSala.tema ? window.game._dadosSala.tema : "custom";
  94. const count = window.wordList[theme].length;
  95. document.getElementById('wordCount').textContent = `Words (${theme}): ${count}`;
  96. }
  97.  
  98. // Add save button event listener
  99. document.getElementById('saveWordsBtn').addEventListener('click', () => {
  100. saveWordListToFile();
  101. });
  102.  
  103. // Add import functionality
  104. document.getElementById('importWords').addEventListener('change', (e) => {
  105. const file = e.target.files[0];
  106. if (file) {
  107. const fileName = file.name;
  108. const themeMatch = fileName.match(/^(.+)_words\.txt$/);
  109. const theme = themeMatch ? themeMatch[1] : "custom"; // Extract theme from filename, e.g., "General (tr)"
  110.  
  111. // Check if the theme exists in wordList, if not, create it
  112. if (!window.wordList[theme]) {
  113. window.wordList[theme] = [];
  114. }
  115.  
  116. const reader = new FileReader();
  117. reader.onload = function(event) {
  118. const text = event.target.result;
  119. const importedWords = text.split('\n').map(word => word.trim()).filter(word => word.length > 0);
  120.  
  121. // Add imported words to the extracted theme category, avoiding duplicates
  122. importedWords.forEach(word => {
  123. if (!window.wordList[theme].includes(word)) {
  124. window.wordList[theme].push(word);
  125. }
  126. });
  127.  
  128. // Update the word count display (uses current room theme)
  129. updateWordCount();
  130. alert(`Imported ${importedWords.length} words into "${theme}" category. Total unique words in "${theme}": ${window.wordList[theme].length}`);
  131. };
  132. reader.readAsText(file);
  133. }
  134. });
  135.  
  136. // Check for game object and collect words + auto-skip
  137. const checkGame = setInterval(() => {
  138. if (window.game && window.game._socket) {
  139. clearInterval(checkGame);
  140.  
  141. // Collect words when your turn comes (event 16) and auto-skip
  142. window.game._socket.on(16, (word1, hints1, word2, hints2) => {
  143. const theme = window.game._dadosSala.tema || "custom";
  144.  
  145. // Add words to the appropriate category if not already present
  146. if (!window.wordList[theme].includes(word1)) {
  147. window.wordList[theme].push(word1);
  148. }
  149. if (!window.wordList[theme].includes(word2)) {
  150. window.wordList[theme].push(word2);
  151. }
  152.  
  153. // Update the word count display
  154. updateWordCount();
  155.  
  156. // Auto-skip after collecting words
  157. setTimeout(() => {
  158. if (window.game && window.game._socket && window.game._codigo) {
  159. window.game._socket.emit(25, window.game._codigo);
  160. }
  161. }, 500); // 500ms delay to ensure words are processed
  162. });
  163.  
  164. // Collect the word when a turn ends and the answer is revealed (event 18 - intervalo)
  165. window.game._socket.on(18, (answer) => {
  166. if (answer) { // Only collect if answer is provided (not null/undefined)
  167. const theme = window.game._dadosSala.tema || "custom";
  168.  
  169. // Add the word if not already present
  170. if (!window.wordList[theme].includes(answer)) {
  171. window.wordList[theme].push(answer);
  172. }
  173.  
  174. // Update the word count display
  175. updateWordCount();
  176. }
  177. });
  178.  
  179. // Initial word count update
  180. updateWordCount();
  181. }
  182. }, 100);
  183.  
  184. })();