您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Greasy Fork is available in English.
Bookmark your favorite skins! Use skin shortcuts! Go crazy with cell animations! Improved chat log! Dance! Use chat replacements! Display the time!
当前为
// ==UserScript== // @name Miracle Scripts // @namespace Miracle Scripts // @version 2.4.3 // @description Bookmark your favorite skins! Use skin shortcuts! Go crazy with cell animations! Improved chat log! Dance! Use chat replacements! Display the time! // @homepage http://agarioforums.net/member.php?action=profile&uid=21263 // @author You // @license MIT // @icon https://abload.de/img/mh3k8o.png // @match *://agma.io/ // @grant none // ==/UserScript== (function() { 'use strict'; window.miracleScripts = { // Source: http://stackoverflow.com/questions/1772179/get-character-value-from-keycode-in-javascript-then-trim#answer-23377822 keyboardMap: [ '', // [0] '', // [1] '', // [2] 'CANCEL', // [3] '', // [4] '', // [5] 'HELP', // [6] '', // [7] 'BACK_SPACE', // [8] 'TAB', // [9] '', // [10] '', // [11] 'CLEAR', // [12] 'ENTER', // [13] 'ENTER_SPECIAL', // [14] '', // [15] 'SHIFT', // [16] 'CONTROL', // [17] 'ALT', // [18] 'PAUSE', // [19] 'CAPS_LOCK', // [20] 'KANA', // [21] 'EISU', // [22] 'JUNJA', // [23] 'FINAL', // [24] 'HANJA', // [25] '', // [26] 'ESCAPE', // [27] 'CONVERT', // [28] 'NONCONVERT', // [29] 'ACCEPT', // [30] 'MODECHANGE', // [31] 'SPACE', // [32] 'PAGE_UP', // [33] 'PAGE_DOWN', // [34] 'END', // [35] 'HOME', // [36] 'LEFT', // [37] 'UP', // [38] 'RIGHT', // [39] 'DOWN', // [40] 'SELECT', // [41] 'PRINT', // [42] 'EXECUTE', // [43] 'PRINTSCREEN', // [44] 'INSERT', // [45] 'DELETE', // [46] '', // [47] '0', // [48] '1', // [49] '2', // [50] '3', // [51] '4', // [52] '5', // [53] '6', // [54] '7', // [55] '8', // [56] '9', // [57] 'COLON', // [58] 'SEMICOLON', // [59] 'LESS_THAN', // [60] 'EQUALS', // [61] 'GREATER_THAN', // [62] 'QUESTION_MARK', // [63] 'AT', // [64] 'A', // [65] 'B', // [66] 'C', // [67] 'D', // [68] 'E', // [69] 'F', // [70] 'G', // [71] 'H', // [72] 'I', // [73] 'J', // [74] 'K', // [75] 'L', // [76] 'M', // [77] 'N', // [78] 'O', // [79] 'P', // [80] 'Q', // [81] 'R', // [82] 'S', // [83] 'T', // [84] 'U', // [85] 'V', // [86] 'W', // [87] 'X', // [88] 'Y', // [89] 'Z', // [90] 'OS_KEY', // [91] Windows Key (Windows) or Command Key (Mac) '', // [92] 'CONTEXT_MENU', // [93] '', // [94] 'SLEEP', // [95] 'NUMPAD0', // [96] 'NUMPAD1', // [97] 'NUMPAD2', // [98] 'NUMPAD3', // [99] 'NUMPAD4', // [100] 'NUMPAD5', // [101] 'NUMPAD6', // [102] 'NUMPAD7', // [103] 'NUMPAD8', // [104] 'NUMPAD9', // [105] 'MULTIPLY', // [106] 'ADD', // [107] 'SEPARATOR', // [108] 'SUBTRACT', // [109] 'DECIMAL', // [110] 'DIVIDE', // [111] 'F1', // [112] 'F2', // [113] 'F3', // [114] 'F4', // [115] 'F5', // [116] 'F6', // [117] 'F7', // [118] 'F8', // [119] 'F9', // [120] 'F10', // [121] 'F11', // [122] 'F12', // [123] 'F13', // [124] 'F14', // [125] 'F15', // [126] 'F16', // [127] 'F17', // [128] 'F18', // [129] 'F19', // [130] 'F20', // [131] 'F21', // [132] 'F22', // [133] 'F23', // [134] 'F24', // [135] '', // [136] '', // [137] '', // [138] '', // [139] '', // [140] '', // [141] '', // [142] '', // [143] 'NUM_LOCK', // [144] 'SCROLL_LOCK', // [145] 'WIN_OEM_FJ_JISHO', // [146] 'WIN_OEM_FJ_MASSHOU', // [147] 'WIN_OEM_FJ_TOUROKU', // [148] 'WIN_OEM_FJ_LOYA', // [149] 'WIN_OEM_FJ_ROYA', // [150] '', // [151] '', // [152] '', // [153] '', // [154] '', // [155] '', // [156] '', // [157] '', // [158] '', // [159] 'CIRCUMFLEX', // [160] 'EXCLAMATION', // [161] 'DOUBLE_QUOTE', // [162] 'HASH', // [163] 'DOLLAR', // [164] 'PERCENT', // [165] 'AMPERSAND', // [166] 'UNDERSCORE', // [167] 'OPEN_PAREN', // [168] 'CLOSE_PAREN', // [169] 'ASTERISK', // [170] 'PLUS', // [171] 'PIPE', // [172] 'HYPHEN_MINUS', // [173] 'OPEN_CURLY_BRACKET', // [174] 'CLOSE_CURLY_BRACKET', // [175] 'TILDE', // [176] '', // [177] '', // [178] '', // [179] '', // [180] 'VOLUME_MUTE', // [181] 'VOLUME_DOWN', // [182] 'VOLUME_UP', // [183] '', // [184] '', // [185] 'SEMICOLON', // [186] 'EQUALS', // [187] 'COMMA', // [188] 'MINUS', // [189] 'PERIOD', // [190] 'SLASH', // [191] 'BACK_QUOTE', // [192] '', // [193] '', // [194] '', // [195] '', // [196] '', // [197] '', // [198] '', // [199] '', // [200] '', // [201] '', // [202] '', // [203] '', // [204] '', // [205] '', // [206] '', // [207] '', // [208] '', // [209] '', // [210] '', // [211] '', // [212] '', // [213] '', // [214] '', // [215] '', // [216] '', // [217] '', // [218] 'OPEN_BRACKET', // [219] 'BACK_SLASH', // [220] 'CLOSE_BRACKET', // [221] 'QUOTE', // [222] '', // [223] 'META', // [224] 'ALTGR', // [225] '', // [226] 'WIN_ICO_HELP', // [227] 'WIN_ICO_00', // [228] '', // [229] 'WIN_ICO_CLEAR', // [230] '', // [231] '', // [232] 'WIN_OEM_RESET', // [233] 'WIN_OEM_JUMP', // [234] 'WIN_OEM_PA1', // [235] 'WIN_OEM_PA2', // [236] 'WIN_OEM_PA3', // [237] 'WIN_OEM_WSCTRL', // [238] 'WIN_OEM_CUSEL', // [239] 'WIN_OEM_ATTN', // [240] 'WIN_OEM_FINISH', // [241] 'WIN_OEM_COPY', // [242] 'WIN_OEM_AUTO', // [243] 'WIN_OEM_ENLW', // [244] 'WIN_OEM_BACKTAB', // [245] 'ATTN', // [246] 'CRSEL', // [247] 'EXSEL', // [248] 'EREOF', // [249] 'PLAY', // [250] 'ZOOM', // [251] '', // [252] 'PA1', // [253] 'WIN_OEM_CLEAR', // [254] '' // [255] ], // Don't remove the spaces, they are used as separators! Source: https://emojiterra.com/de/liste/ emojis: '😀 😃 😄 😁 😆 😅 😂 😉 😊 😇 😍 😘 😗 ☺️ 😚 😙 😋 😛 😜 😝 😐 😑 😶 😏 😒 😬 😌 😔 😪 😴 😷 😵 😎 😕 😟 😮 😯 😲 😳 😦 😧 😨 😰 😥 😢 😭 😱 😖 😣 😞 😓 😩 😫 😤 😡 😠 😈 👿 💀 💩 👹 👺 👻 👽 👾 😺 😸 😹 😻 😼 😽 🙀 😿 😾 🙈 🙉 🙊 💋 💌 💘 💝 💖 💗 💓 💞 💕 💟 💔 ❤️ 💛 💚 💙 💜 💯 💢 💥 💫 💦 💨 💣 💬 💭 💤 👋 ✋ 👌 ✌️ 👈 👉 👆 👇 ☝️ 👍 👎 ✊ 👊 👏 🙌 👐 🙏 💅 💪 👂 👃 👀 👅 👄 👶 👦 👧 👱 👨 👩 👴 👵 🙍 🙎 🙅 🙆 💁 🙋 🙇 👮 💂 👷 👸 👳 👲 👰 👼 🎅 💆 💇 🚶 🏃 💃 👯 🏇 🏂 🏄 🚣 🏊 🚴 🚵 🛀 👭 👫 👬 💏 💑 👪 👤 👥 👣 🐵 🐒 🐶 🐕 🐩 🐺 🐱 🐈 🐯 🐅 🐆 🐴 🐎 🐮 🐂 🐃 🐄 🐷 🐖 🐗 🐽 🐏 🐑 🐐 🐪 🐫 🐘 🐭 🐁 🐀 🐹 🐰 🐇 🐻 🐨 🐼 🐾 🐔 🐓 🐣 🐤 🐥 🐦 🐧 🐸 🐊 🐢 🐍 🐲 🐉 🐳 🐋 🐬 🐟 🐠 🐡 🐙 🐚 🐌 🐛 🐜 🐝 🐞 💐 🌸 💮 🌹 🌺 🌻 🌼 🌷 🌱 🌲 🌳 🌴 🌵 🌾 🌿 🍀 🍁 🍂 🍃 🍇 🍈 🍉 🍊 🍋 🍌 🍍 🍎 🍏 🍐 🍑 🍒 🍓 🍅 🍆 🌽 🍄 🌰 🍞 🍖 🍗 🍔 🍟 🍕 🍳 🍲 🍱 🍘 🍙 🍚 🍛 🍜 🍝 🍠 🍢 🍣 🍤 🍥 🍡 🍦 🍧 🍨 🍩 🍪 🎂 🍰 🍫 🍬 🍭 🍮 🍯 🍼 ☕ 🍵 🍶 🍷 🍸 🍹 🍺 🍻 🍴 🔪 🌍 🌎 🌏 🌐 🗾 🌋 🗻 🏠 🏡 🏢 🏣 🏤 🏥 🏦 🏨 🏩 🏪 🏫 🏬 🏭 🏯 🏰 💒 🗼 🗽 ⛪ ⛲ ⛺ 🌁 🌃 🌄 🌅 🌆 🌇 🌉 ♨️ 🎠 🎡 🎢 💈 🎪 🚂 🚃 🚄 🚅 🚆 🚇 🚈 🚉 🚊 🚝 🚞 🚋 🚌 🚍 🚎 🚐 🚑 🚒 🚓 🚔 🚕 🚖 🚗 🚘 🚙 🚚 🚛 🚜 🚲 🚏 ⛽ 🚨 🚥 🚦 🚧 ⚓ ⛵ 🚤 🚢 ✈️ 💺 🚁 🚟 🚠 🚡 🚀 ⌛ ⏳ ⌚ ⏰ 🕛 🕧 🕐 🕜 🕑 🕝 🕒 🕞 🕓 🕟 🕔 🕠 🕕 🕡 🕖 🕢 🕗 🕣 🕘 🕤 🕙 🕥 🕚 🕦 🌑 🌒 🌓 🌔 🌕 🌖 🌗 🌘 🌙 🌚 🌛 🌜 ☀️ 🌝 🌞 ⭐ 🌟 🌠 🌌 ☁️ ⛅ 🌀 🌈 🌂 ☔ ⚡ ❄️ ⛄ 🔥 💧 🌊 🎃 🎄 🎆 🎇 ✨ 🎈 🎉 🎊 🎋 🎍 🎎 🎏 🎐 🎑 🎀 🎁 🎫 🏆 ⚽ ⚾ 🏀 🏈 🏉 🎾 🎳 ⛳ 🎣 🎽 🎿 🎯 🎱 🔮 🎮 🎰 🎲 ♠️ ♥️ ♦️ ♣️ 🃏 🀄 🎴 🎭 🎨 👓 👔 👕 👖 👗 👘 👙 👚 👛 👜 👝 🎒 👞 👟 👠 👡 👢 👑 👒 🎩 🎓 💄 💍 💎 🔇 🔈 🔉 🔊 📢 📣 📯 🔔 🔕 🎼 🎵 🎶 🎤 🎧 📻 🎷 🎸 🎹 🎺 🎻 📱 📲 ☎️ 📞 📟 📠 🔋 🔌 💻 💽 💾 💿 📀 🎥 🎬 📺 📷 📹 📼 🔍 🔎 💡 🔦 🏮 📔 📕 📖 📗 📘 📙 📚 📓 📒 📃 📜 📄 📰 📑 🔖 💰 💴 💵 💶 💷 💸 💳 💹 💱 💲 ✉️ 📧 📨 📩 📤 📥 📦 📫 📪 📬 📭 📮 ✏️ ✒️ 📝 💼 📁 📂 📅 📆 📇 📈 📉 📊 📋 📌 📍 📎 📏 📐 ✂️ 🔒 🔓 🔏 🔐 🔑 🔨 🔫 🔧 🔩 🔗 🔬 🔭 📡 💉 💊 🚪 🚽 🚿 🛁 🚬 🗿 🏧 🚮 🚰 ♿ 🚹 🚺 🚻 🚼 🚾 🛂 🛃 🛄 🛅 ⚠️ 🚸 ⛔ 🚫 🚳 🚭 🚯 🚱 🚷 📵 🔞 ⬆️ ↗️ ➡️ ↘️ ⬇️ ↙️ ⬅️ ↖️ ↕️ ↔️ 🔃 🔄 🔙 🔚 🔛 🔜 🔝 🔯 ♈ ♉ ♊ ♋ ♌ ♍ ♎ ♏ ♐ ♑ ♒ ♓ ⛎ 🔀 🔁 🔂 ▶️ ◀️ 🔼 🔽 🎦 📶 📳 📴 ♻️ 🔱 📛 🔰 ⭕ ✅ ☑️ ✖️ ❌ ❎ ➕ ➖ ➗ ➰ ➿ 〽️ ✳️ ✴️ ❇️ ‼️ ⁉️ ❓ ❔ ❕ ❗ 〰️ ©️ ®️ ™️ 🔠 🔡 🔢 🔣 🔤 🅰️ 🆎 🅱️ 🆑 🆒 🆓 🆔 Ⓜ️ 🆕 🆖 🅾️ 🆗 🅿️ 🆘 🆙 🆚 🈁 🈂️ 🈷️ 🈶 🈯 🉐 🈹 🈚 🈲 🉑 🈸 🈴 🈳 ㊗️ ㊙️ 🈺 🈵 🔴 🔵 ⚫ ⚪ ⬛ ⬜ ◼️ ◻️ ◾ ◽ ▪️ ▫️ 🔶 🔷 🔸 🔹 🔺 🔻 💠 🔘 🔳 🔲 🏁 🚩 🎌', init: function() { this.setupPolyfills(); this.config(); this.animation(); this.chatLog(); this.dance(); this.favSkins(); this.paste(); this.replacements(); this.fpsPing(); this.timer(); this.skinChanger(); this.lineSplit(); this.waste(); this.nameColor(); this.help(); this.commands(); console.log('🌸 Miracle Scripts successfully loaded!'); }, config: function() { var self = this; var settings; var loadSettings = function (stringifiedSettings) { var defaultSettings = { // To get keycodes: https://keycode.info bindings: { animation: 17, // CTRL paste: 33, // PAGE UP dance: 34, // PAGE DOWN, chatLog: 76, // L }, replacements: ":D|:smile:\n:*(|:sob:\n:'D|:sweat_smiley:\nxD|:joy:", primaryColor: '#FF69B4', targetLanguage: 'EN', favSkins: [], }; if (stringifiedSettings == null) { settings = defaultSettings; localStorage.setItem('miracleScripts', JSON.stringify(settings)); } else { settings = JSON.parse(stringifiedSettings); // Update for settings: if (typeof settings.primaryColor === 'undefined') { settings.primaryColor = defaultSettings.primaryColor; localStorage.setItem('miracleScripts', JSON.stringify(settings)); } if (typeof settings.bindings.chatLog === 'undefined') { settings.bindings.chatLog = defaultSettings.bindings.chatLog; localStorage.setItem('miracleScripts', JSON.stringify(settings)); } if (typeof settings.favSkins === 'undefined') { settings.favSkins = defaultSettings.favSkins; localStorage.setItem('miracleScripts', JSON.stringify(settings)); } if (typeof settings.targetLanguage === 'undefined') { settings.targetLanguage = defaultSettings.targetLanguage; localStorage.setItem('miracleScripts', JSON.stringify(settings)); } if (typeof settings.quickSkins === 'undefined') { settings.quickSkins = []; localStorage.setItem('miracleScripts', JSON.stringify(settings)); } if (typeof settings.nameChangeDelay === 'undefined') { settings.nameChangeDelay = 1000; localStorage.setItem('miracleScripts', JSON.stringify(settings)); } if (typeof settings.installedVersion === 'undefined') { settings.installedVersion = 1; localStorage.setItem('miracleScripts', JSON.stringify(settings)); } } }; loadSettings(localStorage.getItem('miracleScripts')); if (settings.installedVersion < this.getVersionAsInt()) { if (settings.installedVersion < this.getVersionAsInt('2.4.3')) { window.alert('📢 Miracle Scripts Update: \n\n' + 'As of version 2.4.3 the nickname color change feature has been removed ' + 'according to an official decision of the Agma team.\n\n' + 'To avoid trouble for its users Miracle Scripts respects this decision. ' + 'Therefore Miracle Scripts is a legit extension for Agma and using it is safe.' ); } settings.installedVersion = this.getVersionAsInt(); localStorage.setItem('miracleScripts', JSON.stringify(settings)); } var applyPrimaryColor = function () { var primaryColorCss = '.miracle-primary-color-font { color: ' + settings.primaryColor + ' !important } .miracle-primary-color-background { background-color: ' + settings.primaryColor + ' !important }; '; $('body').append('<style>' + primaryColorCss + '</style>'); }; applyPrimaryColor(); // We need to have a delay, because the menu is not loaded right away setTimeout(function () { var $playButton = $('#playBtn'); var $specateButton = $('#spectateBtn'); $playButton.get(0).style.width = '40%'; $specateButton.get(0).style.width = '40%'; var $settingsButton = $('<button class="spec" style="width: 40px; margin-left: 7px; text-align: center; padding: 10px 0 20px 0" title="Miracle Scripts Settings">📜</button>'); $settingsButton.insertAfter($playButton); var changeKey = function (event) { var name = this.name.substr(4); $(this).val(self.keyboardMap[event.keyCode]); settings.bindings[name] = event.keyCode; localStorage.setItem('miracleScripts', JSON.stringify(settings)); }; var deleteKey = function () { var action = $(this).attr('data-action'); $('#miracle-settings input[name=key_' + action + ']').val('undefined'); settings.bindings[action] = null; localStorage.setItem('miracleScripts', JSON.stringify(settings)); }; // Weird Agma scripting... press enter in the replacements textarea and the chat box gets focused! // Therefore catch the keydown event (that happens earlier) and insert the linebreak manually, // focus again (delayed) and go to the end of the text where the linebreak is. // We can improve this later on... var addReturn = function (event) { if (event.keyCode === 13) { var textarea = this; $(textarea).text($(this).text() + '\n').focus(); setTimeout(function () { $(textarea).focus(); textarea.setSelectionRange(textarea.value.length, textarea.value.length); }, 1); } }; var changeReplacements = function () { settings.replacements = $(this).val(); localStorage.setItem('miracleScripts', JSON.stringify(settings)); }; var changePrimaryColor = function () { settings.primaryColor = $(this).val(); localStorage.setItem('miracleScripts', JSON.stringify(settings)); applyPrimaryColor(); }; var changeTargetLanguage = function () { settings.targetLanguage = $(this).val(); localStorage.setItem('miracleScripts', JSON.stringify(settings)); }; var $modal = $('<div id="miracle-settings" class="miracle-primary-color-font" style="position: fixed; width: 100%; height: 100%; padding: 50px; background-color: rgba(0,0,0,0.95); z-index: 999; display: none"></div>'); $modal.append('<h1>Miracle Scripts Settings</h1>'); if (GM_info) { $modal.append('<small style="color: #717171">Version ' + GM_info.script.version + '</small>'); } var $element = $('<input name="key_animation" value="' + self.keyboardMap[settings.bindings.animation] + '"/>').keyup(changeKey); $modal.append('<br><br>Animation-Key:<br>', $element); $element = $('<a href="#" data-action="animation" class="miracle-primary-color-background" style="display: inline-block; padding: 3px 10px; color: white">✖</a>').click(deleteKey); $modal.append($element); $element = $('<input name="key_paste" value="' + self.keyboardMap[settings.bindings.paste] + '"/>').keyup(changeKey); $modal.append('<br>Paste-Key:<br>', $element); $element = $('<a href="#" data-action="paste" class="miracle-primary-color-background" style="display: inline-block; padding: 3px 10px; color: white">✖</a>').click(deleteKey); $modal.append($element); $element = $('<input name="key_dance" value="' + self.keyboardMap[settings.bindings.dance] + '"/>').keyup(changeKey); $modal.append('<br>Dance-Key:<br>', $element); $element = $('<a href="#" data-action="dance" class="miracle-primary-color-background" style="display: inline-block; padding: 3px 10px; color: white">✖</a>').click(deleteKey); $modal.append($element); $element = $('<input name="key_chatLog" value="' + self.keyboardMap[settings.bindings.chatLog] + '"/>').keyup(changeKey); $modal.append('<br>Chat-Log-Key:<br>', $element); $element = $('<a href="#" data-action="chatLog" class="miracle-primary-color-background" style="display: inline-block; padding: 3px 10px; color: white">✖</a>').click(deleteKey); $modal.append($element); $element = $('<select name="target_language"><option value="en">English</option><option value="de">German</option><option value="fr">French</option><option value="es">Spanish</option><option value="it">Italian</option><option value="nl">Dutch</option><option value="pl">Polish</option><option value="pt">Portuguese</option><option value="ru">Russian</option></select>').change(changeTargetLanguage); $modal.append('<br><br>Translate chat messages to:<br>', $element); $element.get(0).value = settings.targetLanguage; $element = $('<input type="color" name="favcolor" value="' + settings.primaryColor + '"/>').change(changePrimaryColor); $modal.append('<br><br>User interface color:<br>', $element); $element = $('<textarea rows="6" style="width: 100%; max-width: 500px" placeholder="search|replace">').text(settings.replacements).keydown(addReturn).keyup(changeReplacements); $modal.append('<br><br>Chat-Replacements (1 per line):<br>', $element, '<br>💡 <span style="color: #717171">Avoid using the search text in the replacement!</span>'); $modal.append($('<br><a href="#" class="miracle-primary-color-background" style="display: inline-block; margin-top: 20px; padding: 10px; color: white">Close</a>').click(function () { $modal.hide(); })); $modal.append($('<a href="#" class="miracle-primary-color-background" style="display: inline-block; margin-left: 20px; margin-top: 20px; padding: 10px; color: white">Export settings</a>').click(function () { self.download('miracle_settings.txt', localStorage.getItem('miracleScripts')); })); $modal.append($('<a href="#" class="miracle-primary-color-background" style="display: inline-block; margin-left: 20px; margin-top: 20px; padding: 10px; color: white">Import settings</a>').click(function () { var stringifiedSettings = window.prompt('Paste the settings here'); if (stringifiedSettings !== null) { loadSettings(stringifiedSettings); localStorage.setItem('miracleScripts', stringifiedSettings); $modal.hide(); self.message('Settings loaded! Reload Agma to refresh. 😄'); } })); $modal.append($('<a href="http://agarioforums.net/showthread.php?tid=61388" target="_blank" class="miracle-primary-color-background" style="display: inline-block; margin-left: 20px; margin-top: 20px; padding: 10px; color: white">Support</a>')); $modal.append($('<a href="#" class="miracle-primary-color-background" style="display: inline-block; margin-left: 20px; margin-top: 20px; padding: 10px; color: white">Help</a>').click(function () { $modal.hide(); self.$helpModal.show(); })); $('body').append($modal); $settingsButton.click(function (event) { $modal.show(); event.preventDefault(); }); }, 500); }, animation: function () { var self = this; var chatAnimate = function () { if ($('#chtbox').val().substr(0, 4) === '/pm ') { self.message('Cannot send animation commands in private chat. 😢', true); return; } // All available commands and combinations var items = ['wacky', 'spin', 'spinspin', 'spinspinspin', 'wackyspin', 'wackyspinspin', 'wackyspinspinspin', 'flip', 'flipflip', 'flipflipflip', 'wackyflip', 'wackyflipflip', 'wackyflipflipfip', 'shake', 'shakeshake', 'shakeshakeshake', 'wackyshake', 'wackyshakeshake', 'wackyshakeshakeshake', 'jump', 'jumpjump', 'jumpjumpjump', 'wackyjump', 'wackyjumpjump', 'wackyjumpjumpjump', ]; // Super-combinations!! if (self.getRandomInt(1, 3) === 1) { items = ['jumpspinflip', 'jumpflipshake', 'jumpspinshake', 'spinshakeflip']; } // Choose randomly an item of the items array // Source: https://stackoverflow.com/questions/5915096/get-random-item-from-javascript-array var item = items[Math.floor(Math.random() * items.length)]; // Attempt to avoid triggering spam protection - probably useless :-/ item += String.fromCharCode(8203).repeat(self.getRandomInt(1, 5)); // Add text into the chat box and focus it (Note: actually "/" is no longer necessary) $('#chtbox').val($('#chtbox').val() + item).focus(); // Stop the event so that the pressed key won't be written into the chat box! event.preventDefault(); }; window.addEventListener('keydown', function (event) { // Do nothing if a menu is open if (document.getElementById('overlays').style.display !== 'none' || document.getElementById('advert').style.display !== 'none') { return; } var settings = JSON.parse(localStorage.getItem('miracleScripts')); if (event.keyCode == settings.bindings.animation) { chatAnimate(); } }); }, paste: function () { var emojiFontSize = (window.innerWidth * window.innerHeight > 2000000) ? 24 : 18; var css = '#miracle-emojis .miracle-emoji { display: inline-block; width: 40px; margin: 0 2px 2px 0; padding: 5px; border: 1px solid #333; font-size: ' + emojiFontSize + 'px; }\n' + '#miracle-emojis .miracle-emoji:hover { background-color: #FF69B4 }'; var emojis = this.emojis.split(' '); var emojiCode = ''; emojis.forEach(function (emoji) { emojiCode += '<a href="#" class="miracle-emoji">' + emoji + '</a>'; }); var addEmoji = function () { setTimeout(function () { var $pasteInput = $(document).find('#miracle-emojis input[name=paste]'); // Add text into the chatbox and focus it $('#chtbox').val($('#chtbox').val() + $pasteInput.val()).focus(); }, 200); $modal.hide(); }; var $modal = $('<div id="miracle-emojis" class="miracle-primary-color-font" style="position: fixed; width: 100%; height: 100%; padding: 50px; color: #FF69B4; background-color: rgba(0,0,0,0.95); overflow-y: auto; z-index: 999; display: none"></div>'); $modal.append('<style>' + css + '</style>'); $modal.append('<h1>Insert text or emoji</h1>'); var $pasteInput = $('<input name="paste" value="" placeholder="Click to paste text, or (double)click emoji!" style="width: 300px; max-width: 100%" />'); $modal.append('<br><br>Insert:<br>', $pasteInput); $modal.html($modal.html() + '<br><br>' + emojiCode); $modal.append($('<br><a href="#" class="miracle-primary-color-background" style="display: inline-block; margin-top: 20px; padding: 10px; color: white">Add</a>').click(addEmoji)); $modal.append($('<a href="#" class="miracle-primary-color-background" style="display: inline-block; float: right; margin-top: 20px; padding: 10px; color: white">Cancel</a>').click(function () { $modal.hide(); })); $modal.find('input[name=paste]').click(function () { var text = window.prompt('Please paste your text here!'); if (text !== null) { var $pasteInput = $modal.find('input[name=paste]'); // Add text into the paste input $pasteInput.val($pasteInput.val() + text); } }); $modal.click(function (event) { if (event.target.classList.contains('miracle-emoji')) { var $target = $(this).find('input[name=paste]'); $target.val($target.val() + $(event.target).text()); event.preventDefault(); } }); $modal.dblclick(function (event) { if (event.target.classList.contains('miracle-emoji')) { $('#chtbox').val($('#chtbox').val() + $(event.target).text()).focus(); $(this).hide(); event.preventDefault(); } }); $('body').append($modal); window.addEventListener('keydown', function (event) { // Do nothing if a menu is open if (document.getElementById('overlays').style.display !== 'none' || document.getElementById('advert').style.display !== 'none') { return; } var settings = JSON.parse(localStorage.getItem('miracleScripts')); if (event.keyCode == settings.bindings.paste) { $modal.find('input[name=paste]').val(''); $modal.toggle(); } }); }, replacements: function () { $('#chtbox').keyup(function () { var settings = JSON.parse(localStorage.getItem('miracleScripts')); var lines = settings.replacements.split('\n'); var text = $('#chtbox').val(); lines.forEach(function (line) { var replacement = line.split('|'); if (replacement.length === 2) { text = text.replace(replacement[0], replacement[1]); $('#chtbox').val(text).focus(); } }); }); }, chatLog: function () { var self = this; // We escape the message before we print them, so no one can inject JS code! var htmlEntities = function (str) { return String(str).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"'); }; var originalFillText = CanvasRenderingContext2D.prototype.fillText; var lastChatNickname = null; var lastChatNicknameColor = null; var chatLogCode = ''; var chatLog = []; CanvasRenderingContext2D.prototype.fillText = function () { if (this.canvas.id !== 'leaderboard' && this.canvas.height === 23) { var text = arguments[0]; // Sometimes also numbers (int) are printed so we filter for strings if (typeof text === 'string' && (this.fillStyle !== '#f5f6ce' && this.fillStyle !== '#444444')) { // Dirty fix for the missing icon in the initial welcome messages if (text == '') { text = '📢'; } lastChatNickname = text; lastChatNicknameColor = this.fillStyle; } if (typeof text === 'string' && (this.fillStyle === '#f5f6ce' || this.fillStyle === '#444444')) { // Unfortunately chat messages will be printed more than just once and I don't know // how to identify them, so for now all messages will be stored and only new messages will be shown. // Of course this means messages won't be shown if they are sent more than once (by the same nickname). var found = false; for (var i = 0; i < chatLog.length; i++) { if (chatLog[i].nickname === lastChatNickname && chatLog[i].nicknameColor === lastChatNicknameColor && chatLog[i].message === text) { found = true; break; } } if (!found) { // NOTE: We might have to look for the coordinates of the text to find out the order of the messages (somehow) chatLogCode += '<div><span class="time">' + (new Date().toLocaleTimeString()) + '</span> <span class="nickname" style="color: ' + lastChatNicknameColor + '">' + htmlEntities(lastChatNickname) + '</span>'; chatLogCode += '<span class="message" style="color: #f5f6ce">' + htmlEntities(text) + '</span></div>'; chatLog.push({nickname: lastChatNickname, nicknameColor: lastChatNicknameColor, message: text}); } } } return originalFillText.apply(this, arguments); }; var performSearch = function (searchElement) { var subject = searchElement.value.toLowerCase(); $('#miracle-complete-chatlog div').each(function () { var $entry = $(this); if ($entry.text().toLowerCase().indexOf(subject) === -1 && subject != '') { $entry.hide(); } else { $entry.show(); } }); }; var $modal = $('<div id="miracle-chatlog" class="miracle-primary-color-font" style="position: fixed; width: 100%; height: 100%; padding: 50px; color: #FF69B4; background-color: rgba(0,0,0,0.95); user-select: text; overflow-y: auto; z-index: 999; display: none"></div>'); $modal.append('<style>#miracle-complete-chatlog div:hover { background-color: rgba(255,255,255,0.1) } #miracle-complete-chatlog .time { padding-right: 10px; color: #666; }</style>'); $modal.append('<h1>Complete chatlog</h1><br>'); $modal.append('<div id="miracle-complete-chatlog"></div>'); $modal.append($('<input type="text" style="display: inline-block; position: fixed; right: 20px; bottom: 20px;" placeholder="Type to search">').keyup(function () { performSearch(this); })); $modal.append($('<br><a href="#" class="miracle-primary-color-background" style="display: inline-block; margin-top: 20px; padding: 10px; color: white">Close</a>').click(function () { $modal.hide(); })); $('body').append($modal); $('#miracle-complete-chatlog').dblclick(function (event) { var $clickTarget; // Each chat message is a div with spans in it. Either the spans or the div might be clicked. if (event.target.tagName.toLowerCase() === 'span') { $clickTarget = $(event.target).parent(); } else { $clickTarget = $(event.target); } var message = $clickTarget.find('.message').text(); // Messages usually start with ': ' but we do not want to "translate" it, so we remove it if (message.substr(0, 2) === ': ') { message = message.substr(2); } var settings = JSON.parse(localStorage.getItem('miracleScripts')); window.open('https://www.deepl.com/translator#en/' + settings.targetLanguage + '/' + message); }); window.addEventListener('keyup', function (event) { // Ignore text input field so typing in them is possible if (self.isWritingText()) { return; } var settings = JSON.parse(localStorage.getItem('miracleScripts')); if (event.keyCode == settings.bindings.chatLog) { $('#miracle-complete-chatlog').html(chatLogCode); $modal.toggle(); $modal.get(0).scrollTo(0, $modal.get(0).scrollHeight); } }); }, favSkins: function () { // We need to have a delay, because the menu is not loaded right away setTimeout(function () { var settings = JSON.parse(localStorage.getItem('miracleScripts')); var favIconClick = function () { var id = parseInt($(this).parent().parent().find('button').attr('onclick').substr(11)); if (settings.favSkins.includes(id)) { $(this).addClass('skin-not-fav'); $('#skinUseBtn' + id).parent().find('span').addClass('skin-not-fav'); var index = settings.favSkins.indexOf(id); settings.favSkins.splice(index, 1); } else { $(this).removeClass('skin-not-fav'); settings.favSkins.push(id); } localStorage.setItem('miracleScripts', JSON.stringify(settings)); renderFavSkins(); }; var renderFavSkins = function () { var $skins = null; if ($('#fav-skins').length > 0) { $skins = $('#fav-skins'); $skins.html(''); } else { $skins = $('<div id="fav-skins" style="background-color: #4d4950"></div>'); $skins.insertAfter('#publicSkinsHeader'); $('#fav-skins').click(function (event) { if (event.target.tagName.toLowerCase() === 'span') { favIconClick.apply(event.target); } }); } settings.favSkins.forEach(function (id) { $skins.append('<div style="float: left; padding: 5px;"><img style="border: 1px solid rgba(0,0,0,.25); border-radius: 50%; box-shadow: 0 0 2px #000;" src="skins/' + id + '_lo.png?u=1575650762" alt=""><h4><span style="cursor: pointer">⭐</span></h4><button class="btn btn-primary skinuse-btn" onclick="toggleSkin(' + id + ');">Use</button></div>'); }); $skins.append('<div style="clear: both"></div>'); }; var addFavIcons = function () { var $skins = $('#publicSkinsPage'); $skins.append('<style>.skin-not-fav { opacity: 0.3 }</style>'); $skins.find('h4').each(function () { var $favIcon = $('<span style="cursor: pointer">⭐</span>'); var id = parseInt($(this).parent().find('button').attr('onclick').substr(11)); $favIcon.click(favIconClick); $(this).append($favIcon); if (!settings.favSkins.includes(id)) { $favIcon.addClass('skin-not-fav'); } }); }; var initialized = false; $('#skinsCustomTab, #skinExampleMenu').click(function () { if (!initialized) { var checkState = function () { if ($('#publicSkinsPage').html() !== '') { addFavIcons(); renderFavSkins(); } else { setTimeout(checkState, 30); } }; checkState(); initialized = true; } }); $('#phpSkins').click(function (event) { if (event.target.classList.contains('publicskins-nav-btn')) { addFavIcons(); } }); }, 500); }, skinChanger: function() { var self = this; // When the user changes the skin, display ID of the picked skin var originalToggleSkin = window.toggleSkin; window.toggleSkin = function () { self.message('Picked skin with ID ' + arguments[0]); return originalToggleSkin.apply(this, arguments); }; window.addEventListener('miracleCommand', function(commandEvent) { var settings = JSON.parse(localStorage.getItem('miracleScripts')); var useSkin = function (skinSlot, skinId) { if (skinId) { if (skinId === 'this' || skinId === 'current' || skinId === 'my' || skinId === 'me' || skinId === 'now' || skinId === 'here') { var skinUri = self.getSkinUrl(); skinId = parseInt(skinUri.substr(skinUri.indexOf('skins/') + 6)); } skinId = parseInt(skinId); settings.quickSkins[skinSlot - 1] = skinId; localStorage.setItem('miracleScripts', JSON.stringify(settings)); } else { skinId = settings.quickSkins[skinSlot - 1]; if (!skinId) { self.message('Skin not set yet, set with /skin' + skinSlot + ' id 😊', true); $('#chtbox').val('').focus(); return; } } window.azad(true); setTimeout(function () { $('#skinExampleMenu').click(); var checkLoaded = function () { var loaded = ($('#skinsFree tr').length > 1); if (loaded) { window.toggleSkin(skinId); setTimeout(function () { $('#shopModalDialog button.close').click(); setTimeout(function () { window.setNick(document.getElementById('nick').value); }, 200); }, 200); } else { setTimeout(checkLoaded, 300); } }; checkLoaded(); }, 200); $('#chtbox').val('').focus(); }; if (commandEvent.command === 'skin1' || commandEvent.command === '/skin1') { useSkin(1, commandEvent.argument1); } if (commandEvent.command === 'skin2' || commandEvent.command === '/skin2') { useSkin(2, commandEvent.argument1); } if (commandEvent.command === 'skin3' || commandEvent.command === '/skin3') { useSkin(3, commandEvent.argument1); } if (commandEvent.command === 'skin4' || commandEvent.command === '/skin4') { useSkin(4, commandEvent.argument1); } if (commandEvent.command === 'skin5' || commandEvent.command === '/skin5') { useSkin(5, commandEvent.argument1); } if (commandEvent.command === 'skin6' || commandEvent.command === '/skin6') { useSkin(6, commandEvent.argument1); } if (commandEvent.command === 'skin7' || commandEvent.command === '/skin7') { useSkin(7, commandEvent.argument1); } if (commandEvent.command === 'skin8' || commandEvent.command === '/skin8') { useSkin(8, commandEvent.argument1); } if (commandEvent.command === 'skin9' || commandEvent.command === '/skin9') { useSkin(9, commandEvent.argument1); } if (commandEvent.command === 'skin10' || commandEvent.command === '/skin10') { useSkin(10, commandEvent.argument1); } if (commandEvent.command === 'skin11' || commandEvent.command === '/skin11') { useSkin(11, commandEvent.argument1); } if (commandEvent.command === 'skin12' || commandEvent.command === '/skin12') { useSkin(12, commandEvent.argument1); } if (commandEvent.command === 'skin13' || commandEvent.command === '/skin13') { useSkin(13, commandEvent.argument1); } if (commandEvent.command === 'skin14' || commandEvent.command === '/skin14') { useSkin(14, commandEvent.argument1); } if (commandEvent.command === 'skin15' || commandEvent.command === '/skin15') { useSkin(15, commandEvent.argument1); } }); }, lineSplit: function() { var self = this; window.addEventListener('miracleCommand', function(commandEvent) { if (commandEvent.command === '/linesplit') { self.lineSplitAt = Date.now(); self.message('Linesplit •••••'); var doSplit = function() { if (Date.now() - self.lineSplitAt < 1000) { var factor = Math.min((Date.now() - self.lineSplitAt) / 700, 1); var x = window.innerWidth / 2; var y = factor * (window.innerHeight / 2); $('canvas').trigger($.Event('mousemove', {clientX: x, clientY: y})); window.requestAnimationFrame(doSplit); } else { if (Date.now() - self.lineSplitAt < 3000) { if (self.splitAt === undefined || Date.now() - self.splitAt > 200) { var hotkeys = JSON.parse(localStorage.getItem('hotkeys')); $('body').trigger($.Event('keydown', { keyCode: hotkeys.Space.c})); $('body').trigger($.Event('keyup', { keyCode: hotkeys.Space.c})); self.splitAt = Date.now(); } window.requestAnimationFrame(doSplit); } } }; doSplit(); $('#chtbox').val(''); } }); }, dance: function () { var self = this; var hotkeys = JSON.parse(localStorage.getItem('hotkeys')); window.addEventListener('keydown', function (event) { if (event.keyCode == hotkeys.M.c && ! self.isWritingText()) { self.dancing = false; } }); window.addEventListener('keyup', function () { // Do nothing if a menu is open if (document.getElementById('overlays').style.display !== 'none' || document.getElementById('advert').style.display !== 'none') { return; } var settings = JSON.parse(localStorage.getItem('miracleScripts')); if (event.keyCode == settings.bindings.dance) { self.dancing = ! self.dancing; if (self.dancing) { self.performDance.apply(self); } } }); }, performDance: function () { var self = this ? this : window.miracleScripts; if (self.danceAngle === undefined) { self.danceAngle = 0; } self.danceAngle += 20; if (self.danceAngle > 360) { self.danceAngle = 0; } var distance = Math.floor(Math.min(window.innerWidth, window.innerHeight) / 2); var x = window.innerWidth / 2 + Math.sin(self.danceAngle * Math.PI / 180) * distance; var y = window.innerHeight / 2 + Math.cos(self.danceAngle * Math.PI / 180) * distance; $('canvas').trigger($.Event('mousemove', {clientX: x, clientY: y})); // Stop dancing if dead ... to avoid continuing dancing after next respawn if (document.getElementById('advert').style.display !== 'none') { self.dancing = false; } if (self.dancing) { window.requestAnimationFrame(self.performDance); } }, waste: function() { var self = this; var hotkeys = JSON.parse(localStorage.getItem('hotkeys')); window.addEventListener('keydown', function (event) { if (event.keyCode == hotkeys.M.c && ! self.isWritingText()) { self.wasting = false; } }); window.addEventListener('miracleCommand', function(commandEvent) { if (commandEvent.command === '/waste') { if (self.wasting) { self.wasting = false; self.message('Stopped wasting all mass.'); self.dancing = false; } else { self.wasting = true; self.message('Wasting all mass...'); if (! self.dancing) { self.dancing = true; self.performDance.apply(self); } $('#chtbox').val('spinshakeflip').focus(); } var doWaste = function() { // Stop wasting mass if dead ... to avoid continuing wasting after next respawn if (document.getElementById('advert').style.display !== 'none') { self.wasting = false; } if (! self.wasting) { return; } $('body').trigger($.Event('keydown', { keyCode: hotkeys.W.c})); $('body').trigger($.Event('keyup', { keyCode: hotkeys.W.c})); window.requestAnimationFrame(doWaste); }; doWaste(); } }); }, fpsPing: function () { window.addEventListener('miracleCommand', function(commandEvent) { if (commandEvent.command === 'ping' || commandEvent.command === '/ping') { window.setFPS(1); var pingRating = 'Extremely bad! ❌', ping = $('#ping').text(); if (parseInt(ping) > 0) { if (parseInt(ping) >= 0 && parseInt(ping) < 40) { pingRating = 'Perfect! ✔️'; } if (parseInt(ping) >= 40 && parseInt(ping) < 70) { pingRating = 'Good! ✔️'; } if (parseInt(ping) >= 70 && parseInt(ping) < 120) { pingRating = 'Acceptable! ✔️'; } if (parseInt(ping) >= 120 && parseInt(ping) < 150) { pingRating = 'Bad! ❌'; } if (parseInt(ping) >= 150 && parseInt(ping) < 990) { pingRating = 'Insanity! ❌'; } if (parseInt(ping) >= 990 && parseInt(ping) < 4900) { pingRating = 'THIS IS MADNESS! ❌'; } if (parseInt(ping) > 4900) { pingRating = 'M M M M M M M M M MONSTERPING! ❌'; } } else { ping = '∞ (infinite) '; } $('#chtbox').val('has a ping of: ' + ping + '. ' + pingRating).focus(); } if (commandEvent.command === 'fps' || commandEvent.command === '/fps') { window.setFPS(1); var fpsRating = 'Perfect! ✔️', fps = $('#fps').text(); if (parseInt(fps) > 0) { if (fps >= 0 && fps < 10) { fpsRating = 'Extremely bad! ❌'; } if (fps >= 10 && fps < 30) { fpsRating = 'Bad! ❌'; } if (fps >= 30 && fps < 40) { fpsRating = 'Acceptable! ✔️'; } if (fps >= 40 && fps < 57) { fpsRating = 'Good! ✔️'; } if (fps > 73) { fpsRating = 'Outstanding! ✔️'; } if (fps > 97) { fpsRating = 'Fantastic! ✔️'; } if (fps > 117) { fpsRating = 'GODLIKE! ✔️'; } } else { fpsRating = ''; } $('#chtbox').val('has ' + fps + ' frames per second (fps). ' + fpsRating).focus(); } }); }, timer: function() { var self = this; var timerStartedAt = null; var timerMinutes = null; var timeoutId = null; var updateId = null; var $countdownUi = $('<div style="position: fixed; right: 20px; bottom: 225px; z-index: 9999; color: #3e3e3e; pointer-events: none"></div>'); $('body').append($countdownUi); window.addEventListener('miracleCommand', function(commandEvent) { if (commandEvent.command === 'timer' || commandEvent.command === '/timer') { var argument1 = commandEvent.argument1; var argument2 = commandEvent.argument2; if (argument1) { timerMinutes = parseInt(argument1); if (argument2 === 'h' || argument2 === 'hour' || argument2 === 'hours') { timerMinutes *= 60; } if (timeoutId !== null) { clearTimeout(timeoutId); } if (argument1 === '0' || argument1 === 'reset' || argument1 === 'stop') { self.message('🗑️ Timer removed'); } else { timerStartedAt = Date.now(); var updateUi = function () { var remaining = ((timerStartedAt + timerMinutes * 60 * 1000) - Date.now()) / 1000 / 60; $countdownUi.text('🕒 ' + Math.ceil(remaining) + 'm'); }; updateId = setInterval(updateUi, 10000); updateUi(); timeoutId = setTimeout(function () { timeoutId = null; window.clearInterval(updateId); $countdownUi.text(''); var message = '🕒 Alert! Timer has expired after ' + timerMinutes + ' minutes.'; this.message(message); window.alert(message); }, timerMinutes * 60 * 1000); self.message('🕒 Timer set to ' + timerMinutes + ' minutes'); } } else { if (timeoutId === null) { self.message('🕒 No timer has been set. Set with: /timer minutes', true); } else { var remaining = ((timerStartedAt + timerMinutes * 60 * 1000) - Date.now()) / 1000 / 60; self.message('🕒 ' + Math.round(remaining * 10) / 10 + ' minutes remaining.'); } } $('#chtbox').val('').focus(); } }); }, nameColor: function() { var self = this; window.addEventListener('miracleCommand', function(commandEvent) { if (commandEvent.command === '/namecolor' || commandEvent.command === '/colorname' || commandEvent.command === '/colorchange') { self.message('This feature has been removed.'); $('#chtbox').val(''); } }); }, help: function() { var $modal = $('<div class="miracle-primary-color-font" style="position: fixed; width: 100%; height: 100%; padding: 50px; background-color: rgba(0,0,0,0.95); z-index: 999; display: none"></div>'); $modal.append('<h1>Miracle Scripts Help</h1>'); var helpText = '<br><span style="color: #717171">Available chat commands are: </span><br><br><table>' + '<tr><th style="padding-right: 50px"><i>Command</i></th><th><i>Description</i></th></tr>' + '<tr><td><code>/miraclehelp</code></td><td>show this help</td></tr>' + '<tr><td><code>/miracle</code></td><td>show version info</td></tr>' + '<tr><td><code>/skin<n></code></td><td>change to skin <n></td></tr>' + '<tr><td><code>/skin<n> this</code></td><td>store current skin as skin <n></td></tr>' + '<tr><td><code>/skin<n> <id></code></td><td>store skin with ID <id> as skin <n></td></tr>' + '<tr><td><code>/say <text></code></td><td>send chat message with fancy font</td></tr>' + '<tr><td><code>/say<n> <text></code></td><td>send chat message with fancy font number <n></td></tr>' + '<tr><td><code>/timer <n></code></td><td>set time for <n> minutes</td></tr>' + '<tr><td><code>/timer <n> h</code></td><td>set time for <n> hours</td></tr>' + '<tr><td><code>/timer stop</code></td><td>stop timer</td></tr>' + '<tr><td><code>/fps</code></td><td>send chat message with current fps</td></tr>' + '<tr><td><code>/ping</code></td><td>send chat message with current ping</td></tr>' + '<tr><td><code>/solo</code></td><td>show solo server message</td></tr>' + '<tr><td><code>/dice</code></td><td>roll a dice with 6 sides</td></tr>' + '<tr><td><code>/dice <n></code></td><td>roll a dice with <n> sides</td></tr>' + '<tr><td><code>/linesplit</code></td><td>let your cell make a linesplit</td></tr>' + '<tr><td><code>/waste</code></td><td>waste all your mass</td></tr>' + '</table>'; $modal.append(helpText); $modal.append($('<br><a href="#" class="miracle-primary-color-background" style="display: inline-block; margin-top: 20px; padding: 10px; color: white">Close</a>').click(function () { $modal.hide(); })); $('body').append($modal); this.$helpModal = $modal; window.addEventListener('miracleCommand', function(commandEvent) { if (commandEvent.command === '/miraclehelp') { $('#chtbox').val('').focus(); $modal.show(); } }); }, commands: function () { var self = this; var minutes; var sessionStartedAt = Date.now(); $('#chtbox').keydown(function (event) { if (event.keyCode === 13) { var message = $('#chtbox').val(); var command = message.split(' ')[0]; var argument1 = message.split(' ')[1]; var argument2 = message.split(' ')[2]; if (message === 'time' || command === '/time') { var now = new Date(); $('#chtbox').val('Local time: ' + now.toLocaleString()).focus(); } if (message === 'minutes' || command === '/minutes' || message === 'online' || command === '/online') { minutes = parseInt((Date.now() - sessionStartedAt) / 1000 / 60); if (minutes > 60) { minutes = '' + minutes; minutes = parseInt(minutes / 60) + ' Hours & ' + (minutes % 60); } $('#chtbox').val('has played for: ' + minutes + ' Minutes in the current session').focus(); } if (command === '/solo') { $('#chtbox').val('⚠️⚠️⚠️ SOLO SERVER ⚠️⚠️⚠️ No teaming!! No hay equipo!! Pas d\'équipe!! Kein Teaming!!').focus(); } if (command === '/miracle') { var miracleInfo = 'is using 𝘔𝘪𝘳𝘢𝘤𝘭𝘦 𝘚𝘤𝘳𝘪𝘱𝘵𝘴, version '; if (GM_info) { miracleInfo += GM_info.script.version; } else { miracleInfo += 'unknown'; } $('#chtbox').val(miracleInfo).focus(); } if (command.substr(0, 4) === '/say' || (command === '/party' && argument1.substr(0, 4) === '/say')) { var prefix = ''; if (command === '/party' && argument1.substr(0, 4) === '/say') { prefix = '/party '; message = message.substr(7); } var fontIndex = message.charAt(4) - 1; if (fontIndex === NaN || fontIndex < 0 || fontIndex > Object.getOwnPropertyNames(self.fonts).length - 1) { fontIndex = 1; } $('#chtbox').val(prefix + self.useUnicodeFont(message.substr(message.indexOf(' ') + 1), Object.getOwnPropertyNames(self.fonts)[fontIndex])).focus(); } if (command === '/dice') { var max = (argument1 > 0) ? parseInt(argument1) : 6; var number = self.getRandomInt(1, max); $('#chtbox').val('rolled a dice with ' + max + ' sides. Result: ' + number); } var commandEvent = new Event('miracleCommand'); commandEvent.message = message; commandEvent.command = command; commandEvent.argument1 = argument1; commandEvent.argument2 = argument2; window.dispatchEvent(commandEvent); } }); }, /** * This object is a container for functions that convert english letters and digits to fancy Unicode characters * @see https://en.wikipedia.org/wiki/Mathematical_Alphanumeric_Symbols * @see https://en.wikipedia.org/wiki/Enclosed_Alphanumerics * @see https://en.wikipedia.org/wiki/Enclosed_Alphanumeric_Supplement */ fonts: { doubleStruck : function(charCode) { if (charCode === 67) { return String.fromCodePoint(0x2102); } // C if (charCode === 72) { return String.fromCodePoint(0x210D); } // H if (charCode === 78) { return String.fromCodePoint(0x2115); } // N if (charCode === 80) { return String.fromCodePoint(0x2119); } // P if (charCode === 81) { return String.fromCodePoint(0x211A); } // Q if (charCode === 82) { return String.fromCodePoint(0x211D); } // R if (charCode === 90) { return String.fromCodePoint(0x2124); } // Z if (charCode >= 65 && charCode <= 90) { return String.fromCodePoint(0x1D538 + charCode - 65); } if (charCode >= 97 && charCode <= 122) { return String.fromCodePoint(0x1D552 + charCode - 97); } if (charCode >= 48 && charCode <= 57) { return String.fromCodePoint(0x1D7D8 + charCode - 48); } return String.fromCharCode(charCode); }, monospace : function(charCode) { if (charCode >= 65 && charCode <= 90) { return String.fromCodePoint(0x1D670 + charCode - 65); } if (charCode >= 97 && charCode <= 122) { return String.fromCodePoint(0x1D68A + charCode - 97); } if (charCode >= 48 && charCode <= 57) { return String.fromCodePoint(0x1D7F6 + charCode - 48); } return String.fromCharCode(charCode); }, scriptBold : function(charCode) { if (charCode >= 65 && charCode <= 90) { return String.fromCodePoint(0x1D4D0 + charCode - 65); } if (charCode >= 97 && charCode <= 122) { return String.fromCodePoint(0x1D4EA + charCode - 97); } if (charCode >= 48 && charCode <= 57) { return String.fromCodePoint(0x1D7CE + charCode - 48); } return String.fromCharCode(charCode); }, frakturBold : function(charCode) { if (charCode === 121) { return '𝐲'; } // y if (charCode >= 65 && charCode <= 90) { return String.fromCodePoint(0x1D56C + charCode - 65); } if (charCode >= 97 && charCode <= 122) { return String.fromCodePoint(0x1D586 + charCode - 97); } if (charCode >= 48 && charCode <= 57) { return String.fromCodePoint(0x1D7CE + charCode - 48); } return String.fromCharCode(charCode); }, serifItalic: function(charCode) { if (charCode === 104) { return String.fromCodePoint(0x1D629); } // h if (charCode >= 65 && charCode <= 90) { return String.fromCodePoint(0x1D434 + charCode - 65); } if (charCode >= 97 && charCode <= 122) { return String.fromCodePoint(0x1D44E + charCode - 97); } return String.fromCharCode(charCode); }, circled: function(charCode) { if (charCode >= 65 && charCode <= 90) { return String.fromCodePoint(0x24B6 + charCode - 65); } if (charCode >= 97 && charCode <= 122) { return String.fromCodePoint(0x24D0 + charCode - 97); } if (charCode >= 49 && charCode <= 57) { return String.fromCodePoint(0x2460 + charCode - 49); } return String.fromCharCode(charCode); }, boxed: function(charCode) { if (charCode >= 65 && charCode <= 90) { return String.fromCodePoint(0x1F130 + charCode - 65); } if (charCode >= 97 && charCode <= 122) { return String.fromCodePoint(0x1F130 + charCode - 97); } if (charCode >= 49 && charCode <= 57) { return String.fromCodePoint(0x2460 + charCode - 49); } return String.fromCharCode(charCode); } }, useUnicodeFont: function(text, font) { var converted = ''; for (var i = 0; i < text.length; i++) { converted += this.fonts[font](text.charCodeAt(i)); } return converted; }, isWritingText: function() { return document.activeElement.type === 'text' || document.activeElement.type === 'password' || document.activeElement.type === 'textarea'; }, download: function (filename, text) { var element = document.createElement('a'); element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text)); element.setAttribute('download', filename); element.style.display = 'none'; document.body.appendChild(element); element.click(); document.body.removeChild(element); }, getVersionAsInt: function(stringVersion) { if (stringVersion === undefined) { stringVersion = typeof GM_info !== 'undefined' ? GM_info.script.version : '0'; } var parts = stringVersion.split('.'); if (parts.length === 1) { parts.push('0'); } if (parts.length === 2) { parts.push('0'); } return parseInt(parts[0]) * 1000000 + parseInt(parts[1]) * 1000 + parseInt(parts[2]); }, /** * Returns a random number between min and max (both inclusive) * Source: MDN */ getRandomInt: function (min, max) { return Math.round(Math.random() * (max - min) + min); }, /** * Use the curser div to display a message at the top of the screen. * * @param message * @param isError */ message: function (message, isError) { var curser = document.querySelector('#curser'); curser.textContent = message; curser.style.display = 'block'; curser.style.color = isError ? 'rgb(255, 0, 0)' : 'rgb(0, 192, 0)'; window.setTimeout(function () { curser.style.display = 'none'; }, 5000); }, /** * Returns the URI of my skin or null if not skin has been set. * Use this.skinUrl() to get it. */ getSkinUrl: function() { var skinUrlRaw = $('#skinExampleMenu').css('background-image'); var parts = skinUrlRaw.split('"'); if (parts.length !== 3) { return null; } else { return parts[1]; } }, setupPolyfills: function() { // Polyfill for old browser so they have String.fromCodePoint() if (!String.fromCodePoint) (function(stringFromCharCode) { var fromCodePoint = function(_) { var codeUnits = [], codeLen = 0, result = ""; for (var index=0, len = arguments.length; index !== len; ++index) { var codePoint = +arguments[index]; // correctly handles all cases including `NaN`, `-Infinity`, `+Infinity` // The surrounding `!(...)` is required to correctly handle `NaN` cases // The (codePoint>>>0) === codePoint clause handles decimals and negatives if (!(codePoint < 0x10FFFF && (codePoint>>>0) === codePoint)) throw RangeError("Invalid code point: " + codePoint); if (codePoint <= 0xFFFF) { // BMP code point codeLen = codeUnits.push(codePoint); } else { // Astral code point; split in surrogate halves // https://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae codePoint -= 0x10000; codeLen = codeUnits.push( (codePoint >> 10) + 0xD800, // highSurrogate (codePoint % 0x400) + 0xDC00 // lowSurrogate ); } if (codeLen >= 0x3fff) { result += stringFromCharCode.apply(null, codeUnits); codeUnits.length = 0; } } return result + stringFromCharCode.apply(null, codeUnits); }; try { // IE 8 only supports `Object.defineProperty` on DOM elements Object.defineProperty(String, "fromCodePoint", { "value": fromCodePoint, "configurable": true, "writable": true }); } catch(e) { String.fromCodePoint = fromCodePoint; } }(String.fromCharCode)); }, }; window.miracleScripts.init(); })();