// ==UserScript==
// @name Gartic IO Node Mode Menu
// @namespace http://tampermonkey.net/
// @version 2025-03-09
// @description Tries to cheat by changing the codes of the game
// @author anonimbiri & Gartic-Developers
// @license MIT
// @match https://gartic.io/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=gartic.io
// @run-at document-start
// @grant none
// ==/UserScript==
// I used the word list from 'https://github.com/Gartic-Developers/Gartic-WordList/'.
// Thanks to Gartic Developers for providing this resource. Also, thanks to Qwyua!
(function() {
'use strict';
// Modify appendChild to intercept and alter the game's script
Node.prototype.appendChild = new Proxy(Node.prototype.appendChild, {
apply: function(target, thisArg, argumentsList) {
const node = argumentsList[0];
if (node.nodeName.toLowerCase() === 'script' && node.src && node.src.includes('room')) {
console.log('Hedef script algılandı:', node.src);
fetch(node.src)
.then(response => response.text())
.then(scriptContent => {
let modifiedContent = scriptContent
.replace(
'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})',
'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})'
)
.replace(
'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)',
'this._timerAtivo=setInterval((function(){Date.now()-e._ativo>15e4&&e.active()}),1e3)'
)
.replace(
'e.unlock()}',
'e.unlock();window.game=e;setInterval(()=>{window.game=e},1000);e.on("votekick",(t,i,o)=>{if(i.id===e.me.id){e.votekick(t.id,true);}});}'
);
let blob = new Blob([modifiedContent], { type: 'application/javascript' });
let blobUrl = URL.createObjectURL(blob);
node.src = blobUrl;
node.textContent = '';
return target.apply(thisArg, [node]);
})
.catch(error => {
console.error('Failed to fetch/modify script:', error);
return target.apply(thisArg, argumentsList);
});
return node;
}
return target.apply(thisArg, argumentsList);
}
});
// Inject HTML
const cheatMenuHTML = `
<div class="cheat-menu" id="cheatMenu">
<h2>Cheat Menu</h2>
<div class="checkbox-container">
<input type="checkbox" id="autoGuess">
<label for="autoGuess">Auto Guess</label>
</div>
<div class="input-container" id="autoGuessSpeedContainer" style="display: none;">
<div class="slider-label">Auto Guess Speed</div>
<div class="custom-slider">
<input type="range" id="autoGuessSpeed" min="100" max="5000" value="1000" step="100">
<div class="slider-track"></div>
<span id="speedValue">1s</span>
</div>
</div>
<div class="checkbox-container">
<input type="checkbox" id="customLoad">
<label for="customLoad">Use Custom Word List</label>
</div>
<div class="input-container" id="loadWordListContainer" style="display: none;">
<label for="wordList">Load Custom Word List</label>
<input type="file" id="wordList" accept=".txt">
</div>
<div class="input-container">
<input type="text" id="guessPattern" placeholder="Enter pattern (e.g., ___e___)">
</div>
<div class="hit-list" id="hitList">
<div class="message">No matches found</div>
</div>
<div class="credit">Made by Anonimbiri & Gartic-Developers</div>
</div>
`;
document.body.insertAdjacentHTML('beforeend', cheatMenuHTML);
// Inject CSS
const style = document.createElement('style');
style.textContent = `
@font-face {
font-family: 'Nunito';
src: url('https://fonts.googleapis.com/css2?family=Nunito:wght@400;700;900&display=swap');
}
.cheat-menu {
position: absolute;
top: 20px;
right: 20px;
width: 250px;
background: rgba(30, 30, 47, 0.9);
backdrop-filter: blur(10px);
border-radius: 15px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
padding: 20px;
display: flex;
flex-direction: column;
gap: 15px;
color: #fff;
user-select: none;
cursor: move;
z-index: 1000;
}
.cheat-menu.dragging {
opacity: 0.8;
transition: opacity 0.2s;
}
.cheat-menu h2 {
margin: 0 0 10px;
font-size: 20px;
font-weight: 900;
color: #ff69b4;
text-transform: uppercase;
letter-spacing: 1px;
}
.checkbox-container {
display: flex;
align-items: center;
gap: 10px;
margin: 5px 0;
}
.checkbox-container input[type="checkbox"] {
appearance: none;
width: 20px;
height: 20px;
background: #2a2a4a;
border: 2px solid #ff69b4;
border-radius: 5px;
cursor: pointer;
transition: all 0.3s ease;
}
.checkbox-container input[type="checkbox"]:checked {
background: #ff69b4;
border-color: #ff69b4;
position: relative;
}
.checkbox-container input[type="checkbox"]:checked::after {
content: "✔";
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: #1e1e2f;
font-size: 14px;
}
.checkbox-container label {
font-size: 14px;
color: #a5e2fe;
}
.input-container {
display: flex;
flex-direction: column;
gap: 10px;
}
.input-container input[type="file"] {
display: none;
}
.input-container label {
background: #ff69b4;
padding: 8px 15px;
border-radius: 10px;
text-align: center;
font-size: 14px;
color: #1e1e2f;
cursor: pointer;
transition: background 0.3s ease;
}
.input-container label:hover {
background: #ff85c0;
}
.input-container input[type="text"] {
background: #2a2a4a;
border: 2px solid #ff69b4;
border-radius: 5px;
padding: 8px;
color: #a5e2fe;
font-size: 14px;
}
.slider-label {
font-size: 14px;
color: #a5e2fe;
text-align: left;
font-weight: 700;
letter-spacing: 0.5px;
text-transform: uppercase;
margin-bottom: 5px;
}
.custom-slider {
position: relative;
width: 100%;
height: 20px;
}
.custom-slider input[type="range"] {
-webkit-appearance: none;
width: 100%;
height: 8px;
background: transparent;
position: absolute;
top: 6px;
left: 0;
z-index: 2;
cursor: pointer;
}
.custom-slider .slider-track {
position: absolute;
top: 8px;
left: 0;
width: 100%;
height: 4px;
background: linear-gradient(to right, #ff69b4 0%, #ff69b4 var(--slider-progress, 20%), #2a2a4a var(--slider-progress, 20%), #2a2a4a 100%);
border-radius: 2px;
z-index: 1;
}
.custom-slider input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
width: 16px;
height: 16px;
background: #ff69b4;
border-radius: 50%;
border: 2px solid #1e1e2f;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
cursor: pointer;
transition: transform 0.2s ease, background 0.2s ease;
}
.custom-slider input[type="range"]::-webkit-slider-thumb:hover {
background: #ff85c0;
transform: scale(1.2);
}
.custom-slider input[type="range"]::-webkit-slider-thumb:active {
background: #ff4d94;
}
.custom-slider #speedValue {
position: absolute;
top: 24px;
left: 50%;
transform: translateX(-50%);
font-size: 12px;
color: #a5e2fe;
background: rgba(42, 42, 74, 0.8);
padding: 2px 8px;
border-radius: 10px;
z-index: 2;
}
.hit-list {
max-height: 200px;
overflow-y: auto;
display: flex;
flex-direction: column;
gap: 8px;
padding-right: 5px;
}
.hit-list::-webkit-scrollbar {
width: 6px;
}
.hit-list::-webkit-scrollbar-thumb {
background: #ff69b4;
border-radius: 10px;
}
.hit-list button {
background: rgba(165, 226, 254, 0.2);
border: none;
padding: 10px;
border-radius: 8px;
color: #a5e2fe;
font-size: 14px;
cursor: pointer;
transition: all 0.3s ease;
text-align: left;
position: relative;
}
.hit-list button:hover:not(.tried) {
background: rgba(165, 226, 254, 0.4);
transform: translateX(5px);
}
.hit-list button:active:not(.tried) {
background: #ff69b4;
color: #1e1e2f;
}
.hit-list button.tried {
background: rgba(255, 105, 180, 0.3);
color: #ffccd5;
order: 1;
opacity: 0.85;
}
.hit-list button.tried:hover {
background: rgba(255, 105, 180, 0.5);
transform: none;
}
.hit-list button.tried:active {
background: #ff69b4;
color: #1e1e2f;
}
.hit-list button.tried::after {
content: "✓";
position: absolute;
right: 10px;
top: 50%;
transform: translateY(-50%);
font-size: 12px;
color: #ffccd5;
}
.tried-label {
font-size: 12px;
color: #ff69b4;
text-transform: uppercase;
letter-spacing: 1px;
text-align: center;
padding: 5px 0;
background: rgba(30, 30, 47, 0.8);
border-radius: 5px;
margin: 8px 0;
order: 0;
pointer-events: none;
}
.message {
font-size: 14px;
color: #a5e2fe;
text-align: center;
padding: 10px;
background: rgba(42, 42, 74, 0.5);
border-radius: 8px;
}
.credit {
font-size: 10px;
color: #a5e2fe;
text-align: center;
margin-top: 10px;
opacity: 0.7;
}
`;
document.head.appendChild(style);
// JavaScript functionality
const cheatMenu = document.getElementById('cheatMenu');
const hitList = document.getElementById('hitList');
let isDragging = false;
let initialX, initialY;
let xOffset = 0;
let yOffset = 0;
let triedLabelAdded = false;
const autoGuessCheckbox = document.getElementById('autoGuess');
const autoGuessSpeedContainer = document.getElementById('autoGuessSpeedContainer');
const autoGuessSpeed = document.getElementById('autoGuessSpeed');
const speedValue = document.getElementById('speedValue');
let autoGuessInterval = null;
// WordList configuration
const wordListURLs = {
"General (en)": "https://cdn.jsdelivr.net/gh/Gartic-Developers/Gartic-WordList@master/languages/English/general.json",
"General (tr)": "https://cdn.jsdelivr.net/gh/Gartic-Developers/Gartic-WordList@master/languages/Turkish/general.json"
};
let wordList = { "Custom": [] }; // Sadece Custom başlangıçta boş
// Fetch word list dynamically based on theme
async function fetchWordList(theme) {
if (!wordList[theme] && wordListURLs[theme]) {
try {
const response = await fetch(wordListURLs[theme]);
if (!response.ok) throw new Error(`Failed to fetch ${theme} word list`);
const data = await response.json();
wordList[theme] = data.words || data; // JSON yapısına göre
console.log(`Loaded ${wordList[theme].length} words for ${theme}`);
} catch (error) {
console.error(`Error fetching word list for ${theme}:`, error);
wordList[theme] = [];
}
}
}
// Draggable functionality
cheatMenu.addEventListener('mousedown', startDragging);
document.addEventListener('mousemove', drag);
document.addEventListener('mouseup', stopDragging);
function startDragging(e) {
if (e.target.tagName !== 'INPUT' && e.target.tagName !== 'BUTTON') {
initialX = e.clientX - xOffset;
initialY = e.clientY - yOffset;
isDragging = true;
cheatMenu.classList.add('dragging');
}
}
function drag(e) {
if (isDragging) {
e.preventDefault();
const currentX = e.clientX - initialX;
const currentY = e.clientY - initialY;
xOffset = currentX;
yOffset = currentY;
setTranslate(currentX, currentY, cheatMenu);
}
}
function setTranslate(xPos, yPos, el) {
el.style.transform = `translate(${xPos}px, ${yPos}px)`;
}
function stopDragging() {
isDragging = false;
cheatMenu.classList.remove('dragging');
}
// Show/hide Auto Guess Speed slider and start/stop auto guessing
autoGuessCheckbox.addEventListener('change', (e) => {
autoGuessSpeedContainer.style.display = e.target.checked ? 'flex' : 'none';
if (!e.target.checked) {
stopAutoGuess();
}
});
// Update speed display and slider track when slider changes
autoGuessSpeed.addEventListener('input', (e) => {
const speed = e.target.value;
const min = parseInt(e.target.min);
const max = parseInt(e.target.max);
const progress = ((speed - min) / (max - min)) * 100;
e.target.parentElement.querySelector('.slider-track').style.setProperty('--slider-progress', `${progress}%`);
speedValue.textContent = speed >= 1000 ? `${speed / 1000}s` : `${speed}ms`;
if (autoGuessCheckbox.checked) {
stopAutoGuess();
startAutoGuess();
}
});
// Initial speed display and slider track
const initialSpeed = autoGuessSpeed.value;
const minSpeed = parseInt(autoGuessSpeed.min);
const maxSpeed = parseInt(autoGuessSpeed.max);
const initialProgress = ((initialSpeed - minSpeed) / (maxSpeed - minSpeed)) * 100;
autoGuessSpeed.parentElement.querySelector('.slider-track').style.setProperty('--slider-progress', `${initialProgress}%`);
speedValue.textContent = initialSpeed >= 1000 ? `${initialSpeed / 1000}s` : `${initialSpeed}ms`;
// Auto Guess functionality
function startAutoGuess() {
if (!autoGuessCheckbox.checked) return;
stopAutoGuess();
const speed = parseInt(autoGuessSpeed.value);
autoGuessInterval = setInterval(() => {
const buttons = hitList.querySelectorAll('button:not(.tried)');
if (buttons.length > 0 && window.game && window.game._socket) {
const word = buttons[0].textContent;
buttons[0].classList.add('tried');
window.game._socket.emit(13, window.game._codigo, word);
if (!triedLabelAdded && hitList.querySelectorAll('button.tried').length === 1) {
const triedLabel = document.createElement('div');
triedLabel.classList.add('tried-label');
triedLabel.textContent = 'Tried Words';
hitList.appendChild(triedLabel);
triedLabelAdded = true;
}
hitList.appendChild(buttons[0]);
}
}, speed);
}
function stopAutoGuess() {
if (autoGuessInterval) {
clearInterval(autoGuessInterval);
autoGuessInterval = null;
}
}
// Mark buttons as tried
hitList.addEventListener('click', (e) => {
if (e.target.tagName === 'BUTTON' && !e.target.classList.contains('tried')) {
const button = e.target;
button.classList.add('tried');
if (!triedLabelAdded && hitList.querySelectorAll('button.tried').length === 1) {
const triedLabel = document.createElement('div');
triedLabel.classList.add('tried-label');
triedLabel.textContent = 'Tried Words';
hitList.appendChild(triedLabel);
triedLabelAdded = true;
}
window.game._socket.emit(13, window.game._codigo, button.textContent);
hitList.appendChild(button);
}
});
// Custom Load Word List checkbox toggle
const customLoadCheckbox = document.getElementById('customLoad');
const loadWordListContainer = document.getElementById('loadWordListContainer');
customLoadCheckbox.addEventListener('change', (e) => {
loadWordListContainer.style.display = e.target.checked ? 'flex' : 'none';
updateHitList(guessPatternInput.value.trim());
});
// Handle file upload and add words to wordList["Custom"]
const fileInput = document.getElementById('wordList');
fileInput.addEventListener('change', (e) => {
const file = e.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = function(event) {
const text = event.target.result;
wordList["Custom"] = text.split('\n').map(word => word.trim()).filter(word => word.length > 0);
alert(`Loaded ${wordList["Custom"].length} words into custom list from ${file.name}`);
updateHitList(guessPatternInput.value.trim());
};
reader.readAsText(file);
}
});
// Auto guess functionality
const guessPatternInput = document.getElementById('guessPattern');
guessPatternInput.addEventListener('input', (e) => {
const pattern = e.target.value.trim();
updateHitList(pattern);
});
function updateHitList(pattern) {
hitList.innerHTML = '';
const activeTheme = customLoadCheckbox.checked || !window.game || !window.game._dadosSala || !window.game._dadosSala.tema
? "Custom"
: window.game._dadosSala.tema;
const activeList = wordList[activeTheme] || [];
if (!pattern) {
if (activeList.length === 0) {
const message = document.createElement('div');
message.classList.add('message');
message.textContent = customLoadCheckbox.checked ? 'Load a custom word list first' : 'No words available for this theme';
hitList.appendChild(message);
} else {
activeList.forEach(word => {
const button = document.createElement('button');
button.textContent = word;
hitList.appendChild(button);
});
}
return;
}
const patternWords = pattern.trim().split(/\s+/);
const regexPatterns = patternWords.map(word =>
word
.split('')
.map(char => (char === '_' ? '[\\p{L}\\p{N}]' : char))
.join('')
);
const regex = new RegExp(`^${regexPatterns.join('\\s+')}$`, 'iu');
const matches = activeList.filter(word => regex.test(word));
if (matches.length === 0) {
const message = document.createElement('div');
message.classList.add('message');
message.textContent = 'No matches found';
hitList.appendChild(message);
} else {
matches.forEach(word => {
const button = document.createElement('button');
button.textContent = word;
hitList.appendChild(button);
});
}
}
// Socket event integration with dynamic word list fetching
const checkGame = setInterval(() => {
if (window.game && window.game._socket) {
clearInterval(checkGame);
// Initial fetch based on current theme
const currentTheme = window.game._dadosSala.tema || "Custom";
if (currentTheme !== "Custom") {
fetchWordList(currentTheme).then(() => updateHitList(guessPatternInput.value.trim()));
}
window.game._socket.on(30, (hint, hintNumber) => {
hint = String(hint).replace(/,/g, '');
guessPatternInput.value = hint;
updateHitList(hint);
if (autoGuessCheckbox.checked) {
startAutoGuess();
}
});
window.game._socket.on(19, (roundNumber, isGameOver) => {
guessPatternInput.value = '';
stopAutoGuess();
updateHitList('');
});
window.game._socket.on(15, (playerId) => {
if (playerId === window.game.me.id) {
guessPatternInput.value = '';
stopAutoGuess();
updateHitList('');
}
});
// Theme change detection
let lastTheme = currentTheme;
setInterval(() => {
const newTheme = window.game._dadosSala.tema || "Custom";
if (newTheme !== lastTheme && newTheme !== "Custom") {
lastTheme = newTheme;
fetchWordList(newTheme).then(() => updateHitList(guessPatternInput.value.trim()));
}
}, 1000);
}
}, 100);
})();