');
var $aliasField = $('
').blur(function() {
var alias = $(this).val();
if (player) {
player.alias = alias;
} else {
player = {name: accountName, alias: alias};
self.settings.players.push(player);
}
localStorage.setItem('miracleScripts', JSON.stringify(self.settings));
});
if (player) {
$aliasField.val(player.alias);
}
$editArea.append($aliasField);
var $noteField = $('
').blur(function() {
var note = $(this).val();
if (player) {
player.note = note;
} else {
player = {name: accountName, note: note};
self.settings.players.push(player);
}
localStorage.setItem('miracleScripts', JSON.stringify(self.settings));
});
if (player) {
$noteField.val(player.note);
}
$editArea.append($noteField);
$editArea.insertBefore('.sweet-alert .sa-button-container');
}, 200);
});
},
animation: function () {
var self = this;
var chatAnimate = function () {
if ($('#chtbox').val().substr(0, 4) === '/pm ') {
$('#chtbox').val('');
}
// 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;
}
if (event.keyCode == self.settings.bindings.animation) {
chatAnimate();
}
});
},
paste: function () {
var self = this;
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 += '
' + emoji + '';
});
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 = $('
');
$modal.append('');
$modal.append('
Insert text or emoji
');
var $pasteInput = $('
');
$modal.append('
Insert:
', $pasteInput);
$modal.html($modal.html() + '
' + emojiCode);
$modal.append($('
Add').click(addEmoji));
$modal.append($('
Cancel').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;
}
if (event.keyCode == self.settings.bindings.paste) {
$modal.find('input[name=paste]').val('');
$modal.toggle();
}
});
window.addEventListener('miracleCommand', function(commandEvent) {
if (commandEvent.command === '/paste') {
$modal.find('input[name=paste]').val('');
$modal.toggle();
$('#chtbox').val('');
}
});
},
replacements: function () {
var self = this;
$('#chtbox').keyup(function () {
var lines = self.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, '"');
};
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];
var xPos = arguments[1]; // Usually 3 for nicknames but bigger when a crown, donator icon etc. are displayed
var lineSize = this.canvas.width; // ATTENTION: Not sure if that really is the total size (icons+ nickname + message)
// Sometimes also numbers (int) are printed (probably masses on cells) 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 += '
' + (new Date().toLocaleTimeString()) + ' ' + htmlEntities(lastChatNickname) + '';
chatLogCode += '' + htmlEntities(text) + '
';
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 = $('
');
$modal.append('');
$modal.append('
Complete chatlog
');
$modal.append('
');
$modal.append($('
').keyup(function () {
performSearch(this);
}));
$modal.append($('
Close').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);
}
window.open('https://www.deepl.com/translator#en/' + self.settings.targetLanguage + '/' + message);
});
var showChatlog = function() {
$('#miracle-complete-chatlog').html(chatLogCode);
$modal.toggle();
$modal.get(0).scrollTo(0, $modal.get(0).scrollHeight);
};
window.addEventListener('keyup', function (event) {
// Ignore text input field so typing in them is possible
if (self.isWritingText()) {
return;
}
if (event.keyCode == self.settings.bindings.chatLog) {
showChatlog();
}
});
window.addEventListener('miracleCommand', function(commandEvent) {
if (commandEvent.command === '/chatlog') {
showChatlog();
$('#chtbox').val('');
}
});
},
favSkins: function () {
var self = this;
// We need to have a delay, because the menu is not loaded right away
setTimeout(function () {
var favIconClick = function () {
var id = parseInt($(this).parent().parent().find('button').attr('onclick').substr(11));
if (self.settings.favSkins.includes(id)) {
$(this).addClass('skin-not-fav');
$('#skinUseBtn' + id).parent().find('span').addClass('skin-not-fav');
var index = self.settings.favSkins.indexOf(id);
self.settings.favSkins.splice(index, 1);
} else {
$(this).removeClass('skin-not-fav');
self.settings.favSkins.push(id);
}
localStorage.setItem('miracleScripts', JSON.stringify(self.settings));
renderFavSkins();
};
var renderFavSkins = function () {
var $skins = null;
if ($('#fav-skins').length > 0) {
$skins = $('#fav-skins');
$skins.html('');
} else {
$skins = $('
');
$skins.insertAfter('#publicSkinsHeader');
$('#fav-skins').click(function (event) {
if (event.target.tagName.toLowerCase() === 'span') {
favIconClick.apply(event.target);
}
});
}
self.settings.favSkins.forEach(function (id) {
$skins.append('

⭐
');
});
$skins.append('
');
};
var addFavIcons = function () {
var $skins = $('#publicSkinsPage');
$skins.append('');
$skins.find('h4').each(function () {
var $favIcon = $('
⭐');
var id = parseInt($(this).parent().find('button').attr('onclick').substr(11));
$favIcon.click(favIconClick);
$(this).append($favIcon);
if (! self.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 useSkinFromSlot = 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);
self.settings.quickSkins[skinSlot - 1] = skinId;
localStorage.setItem('miracleScripts', JSON.stringify(self.settings));
} else {
skinId = self.settings.quickSkins[skinSlot - 1];
if (!skinId) {
self.message('Skin not set yet, set with /skin' + skinSlot + ' id 😊', true);
$('#chtbox').val('').focus();
return;
}
}
self.useSkin(skinId);
$('#chtbox').val('').focus();
};
if (commandEvent.command === 'skin1' || commandEvent.command === '/skin1') {
useSkinFromSlot(1, commandEvent.argument1);
}
if (commandEvent.command === 'skin2' || commandEvent.command === '/skin2') {
useSkinFromSlot(2, commandEvent.argument1);
}
if (commandEvent.command === 'skin3' || commandEvent.command === '/skin3') {
useSkinFromSlot(3, commandEvent.argument1);
}
if (commandEvent.command === 'skin4' || commandEvent.command === '/skin4') {
useSkinFromSlot(4, commandEvent.argument1);
}
if (commandEvent.command === 'skin5' || commandEvent.command === '/skin5') {
useSkinFromSlot(5, commandEvent.argument1);
}
if (commandEvent.command === 'skin6' || commandEvent.command === '/skin6') {
useSkinFromSlot(6, commandEvent.argument1);
}
if (commandEvent.command === 'skin7' || commandEvent.command === '/skin7') {
useSkinFromSlot(7, commandEvent.argument1);
}
if (commandEvent.command === 'skin8' || commandEvent.command === '/skin8') {
useSkinFromSlot(8, commandEvent.argument1);
}
if (commandEvent.command === 'skin9' || commandEvent.command === '/skin9') {
useSkinFromSlot(9, commandEvent.argument1);
}
if (commandEvent.command === 'skin10' || commandEvent.command === '/skin10') {
useSkinFromSlot(10, commandEvent.argument1);
}
if (commandEvent.command === 'skin11' || commandEvent.command === '/skin11') {
useSkinFromSlot(11, commandEvent.argument1);
}
if (commandEvent.command === 'skin12' || commandEvent.command === '/skin12') {
useSkinFromSlot(12, commandEvent.argument1);
}
if (commandEvent.command === 'skin13' || commandEvent.command === '/skin13') {
useSkinFromSlot(13, commandEvent.argument1);
}
if (commandEvent.command === 'skin14' || commandEvent.command === '/skin14') {
useSkinFromSlot(14, commandEvent.argument1);
}
if (commandEvent.command === 'skin15' || commandEvent.command === '/skin15') {
useSkinFromSlot(15, commandEvent.argument1);
}
if (commandEvent.command === 'skin16' || commandEvent.command === '/skin16') {
useSkinFromSlot(16, commandEvent.argument1);
}
if (commandEvent.command === 'skin17' || commandEvent.command === '/skin17') {
useSkinFromSlot(17, commandEvent.argument1);
}
if (commandEvent.command === 'skin18' || commandEvent.command === '/skin18') {
useSkinFromSlot(18, commandEvent.argument1);
}
if (commandEvent.command === 'skin19' || commandEvent.command === '/skin19') {
useSkinFromSlot(19, commandEvent.argument1);
}
if (commandEvent.command === 'skin20' || commandEvent.command === '/skin20') {
useSkinFromSlot(20, commandEvent.argument1);
}
if (commandEvent.command === 'skin21' || commandEvent.command === '/skin21') {
self.message('Only 20 skin slots are available ❌', true);
$('#chtbox').val('').focus();
}
});
},
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) {
$('body').trigger($.Event('keydown', { keyCode: self.hotkeys.Space.c}));
$('body').trigger($.Event('keyup', { keyCode: self.hotkeys.Space.c}));
self.splitAt = Date.now();
}
window.requestAnimationFrame(doSplit);
}
}
};
doSplit();
$('#chtbox').val('');
}
});
},
dance: function () {
var self = this;
// Stop dancing on respawn
window.addEventListener('keydown', function (event) {
if (event.keyCode == self.hotkeys.M.c && ! self.isWritingText()) {
self.dancing = false;
}
});
var initDance = function() {
// Do nothing if a menu is open
if (document.getElementById('overlays').style.display !== 'none' || document.getElementById('advert').style.display !== 'none') {
return;
}
self.dancing = ! self.dancing;
if (self.dancing) {
self.performDance.apply(self);
}
};
window.addEventListener('keyup', function () {
if (event.keyCode == self.settings.bindings.dance) {
initDance();
}
});
window.addEventListener('miracleCommand', function(commandEvent) {
if (commandEvent.command === '/dance') {
initDance();
$('#chtbox').val('');
}
});
},
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;
window.addEventListener('keydown', function (event) {
if (event.keyCode == self.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: self.hotkeys.W.c}));
$('body').trigger($.Event('keyup', { keyCode: self.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) < 200) { pingRating = 'Bad! ❌'; }
if (parseInt(ping) >= 200 && 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 = $('
');
$('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();
}
});
},
alive: function() {
var self = this;
var element = document.getElementById('playBtn');
element.addEventListener('click', function() {
if (! self.isAlive) {
self.spawnedAt = Date.now();
self.isAlive = true;
}
});
element = document.querySelector('.bottom-dashboard-box img[title=Respawn]');
element.addEventListener('click', function() {
self.spawnedAt = Date.now();
self.isAlive = true;
});
element = document.getElementById('advertContinue');
element.addEventListener('click', function() {
self.isAlive = false;
});
window.addEventListener('keydown', function (event) {
if (event.keyCode == self.hotkeys.M.c && ! self.isWritingText()) {
self.spawnedAt = Date.now();
self.isAlive = true;
}
});
window.addEventListener('miracleCommand', function(commandEvent) {
if (commandEvent.command === '/alive' || commandEvent.command === 'alive') {
if (! self.isAlive || document.getElementById('advert').style.display !== 'none') {
$('#chtbox').val('is not alive ☠');
} else {
var minutes = parseInt((Date.now() - self.spawnedAt) / 1000 / 60);
if (minutes < 1) {
minutes = parseInt((Date.now() - self.spawnedAt) / 1000) + ' Seconds & 0';
}
if (minutes > 60) {
minutes = parseInt(minutes / 60) + ' Hours & ' + (minutes % 60);
}
$('#chtbox').val('has been alive for ' + minutes + ' Minutes');
}
}
});
},
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 since the Agma staff does not allow it', true);
$('#chtbox').val('');
}
});
},
skinApplier: function() {
var self = this;
var $useSkinItem = $('');
$useSkinItem.insertAfter('#contextPlayer');
$useSkinItem.click(function() {
var skinUrl = self.getSkinUrl('#contextPlayerSkin');
if (skinUrl === null) {
self.message('This player does not use a skin or no player selected 🚫', true);
} else {
var skinId = parseInt(skinUrl.substr(22)); // Cut off "https://agma.io/skins/"
self.useSkin(skinId);
}
});
},
help: function() {
var $modal = $('
');
$modal.append('
Miracle Scripts Help
');
var helpText = '
Available chat commands are: ' +
'Command | Description |
' +
'/help | Show this help |
' +
'/miracle | Show version info |
' +
'/miraclesettings | Show the miracle settings page |
' +
'/skin | Change to skin <n> |
' +
'/skin this | Store current skin as skin |
' +
'/skin <id> | Store skin with ID <id> as skin <n> |
' +
'/skinid | Send a chat message with your skin ID |
' +
'/useskin <id> | Use skin with the given ID |
' +
'/chatlog | Show the extended chat log |
' +
'/say <text> | Send a chat message with a fancy font |
' +
'/say<n> <text> | Send chat message with fancy font number <n> |
' +
'/shout <text> | Purchase a megaphone shout for 20000 coins> |
' +
'/paste | Show the emojis and text paste page |
' +
'/timer <n> | Set timer for <n> minutes |
' +
'/timer <n> h | Set timer for <n> hours |
' +
'/timer stop | Stop the timer |
' +
'/xp | Send a chat message with your level and next level\'s progress |
' +
'/powerups | Send a chat message with your powerup amounts |
' +
'/fps | Send a chat message with current fps |
' +
'/ping | Send a chat message with current ping |
' +
'/online | For how long are you online in the current session? |
' +
'/alive | For how long are you alive? |
' +
'/solo | Show the solo server message |
' +
'/dice | Roll a dice with 6 sides |
' +
'/dice <n> | Roll a dice with <n> sides |
' +
'/linesplit | Let your cell make a linesplit |
' +
'/waste | Waste all your mass |
' +
'/dance | Let your cell dance |
' +
'
';
$modal.append(helpText);
$modal.append($('
Close').click(function () {
$modal.hide();
}));
$('body').append($modal);
this.$helpModal = $modal;
window.addEventListener('miracleCommand', function(commandEvent) {
if (commandEvent.command === '/help' || commandEvent.command === '/miraclehelp') {
$('#chtbox').val('').focus();
$modal.show();
}
});
},
commands: function () {
var self = this;
var minutes, skinId;
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') {
if (message === 'minutes' || command === '/minutes') {
self.message('⛔ The /minutes command is deprecated, please use /online instead.', true);
}
minutes = parseInt((Date.now() - sessionStartedAt) / 1000 / 60);
if (minutes < 1) {
minutes = parseInt((Date.now() - self.spawnedAt) / 1000) + ' Seconds & 0';
}
if (minutes > 60) {
minutes = parseInt(minutes / 60) + ' Hours & ' + (minutes % 60);
}
$('#chtbox').val('is online 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 === '/skinid' || command === '/sayskin') {
var skinUri = self.getSkinUrl();
skinId = parseInt(skinUri.substr(skinUri.indexOf('skins/') + 6));
$('#chtbox').val('uses the skin with the ID ' + skinId);
return;
}
if (command === '/useskin') {
skinId = parseInt(argument1);
if (! (skinId > 0)) {
self.message('Invalid skin ID given. Example usage of command: /useskin 123', true);
} else {
self.useSkin(skinId);
}
$('#chtbox').val('');
}
if (command.substr(0, 4) === '/say' || (command === '/party' && argument1.substr(0, 4) === '/say') || (command === '/pm' && argument2.substr(0, 4) === '/say')) {
var prefix = '';
if (command === '/party' && argument1.substr(0, 4) === '/say') {
prefix = '/party ';
message = message.substr(7);
}
if (command === '/pm' && argument2.substr(0, 4) === '/say') {
var spacePos = message.indexOf(' ', 5);
prefix = message.substr(0, spacePos + 1);
message = message.substr(spacePos + 1);
}
var fontIndex = message.charAt(4) - 1;
if (Number.isNaN(fontIndex)|| 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);
}
if (command === '/powerups' || command === '/powers') {
// Note: If the amount of a powerup is 1, no number will be displayed.
var powerups = ($('#invRecombine p').text() || 0) + ' rec, ' +
($('#invSpeed p').text() || ($('#invSpeed').css('display') === 'none' ? 0 : 1)) + ' speed, ' +
($('#invGrowth p').text() || ($('#invGrowth').css('display') === 'none' ? 0 : 1)) + ' growth, ' +
($('#invSpawnVirus p').text() || ($('#invSpawnVirus').css('display') === 'none' ? 0 : 1)) + ' virus, ' +
($('#invSpawnMothercell p').text() || ($('#invSpawnMothercell').css('display') === 'none' ? 0 : 1)) + ' red cell, ' +
($('#invSpawnPortal p').text() || ($('#invSpawnPortal').css('display') === 'none' ? 0 : 1)) + ' portal, ' +
($('#invSpawnGoldOre p').text() || ($('#invSpawnGoldOre').css('display') === 'none' ? 0 : 1)) + ' block, ' +
($('#invFreeze p').text() || ($('#invFreeze').css('display') === 'none' ? 0 : 1)) + ' freeze, ' +
($('#inv360Shot p').text() || ($('#inv360Shot').css('display') === 'none' ? 0 : 1)) + ' push ';
$('#chtbox').val('has ' + powerups);
}
if (command === '/xp' || command === '/progress') {
$('#chtbox').val('is level ' + $('#level2').text() + ' and has ' + $('.xpBarTop span').text() + ' of next level');
}
if (command === '/megaphone' || command === '/megashout' || command === '/shout') {
// Notes: 1-7 = colors. The shout message can have max 130 chars, but chat messages can be only 100(?) chars long so np
self.warnBeforeMegaShout(message.substr(message.indexOf(' ') + 1), self.getRandomInt(1, 7));
$('#chtbox').val('');
}
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 regexResults, emojiPositions = [], emojiRegex = /:\w+:/g;
while ((regexResults = emojiRegex.exec(text)) !== null) {
emojiPositions.push(regexResults.index);
}
var converted = '', convert = true;
for (var i = 0; i < text.length; i++) {
if (! convert && text.charAt(i) === ':') {
convert = true;
}
if (emojiPositions.indexOf(i) !== -1) {
convert = false;
}
if (convert) {
converted += this.fonts[font](text.charCodeAt(i));
} else {
converted += text.charAt(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);
},
swal: function (title, message, html) {
if (html === undefined) {
html = true;
}
window.swal({
title: '📢
' + title + '',
text: message,
html: html
});
},
/**
* Returns the URI of my skin or null if not skin has been set.
* Use this.skinUrl() to get it.
*/
getSkinUrl: function(sourceSelector) {
if (sourceSelector === undefined) {
sourceSelector = '#skinExampleMenu';
}
var skinUrlRaw = $(sourceSelector).css('background-image');
var parts = skinUrlRaw.split('"');
if (parts.length !== 3) {
return null;
} else {
return parts[1];
}
},
useSkin: function(skinId) {
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);
},
/**
* This is an original Agma function but its not accessible so this is a copy.
*/
warnBeforeMegaShout: function(msg, color) {
swal({
title: "Confirm",
text: 'If you click "Buy", you will purchase the megaphone shout.',
type: "warning",
showCancelButton: true,
confirmButtonColor: "#4CAF50",
confirmButtonText: "Yes, confirm purchase",
cancelButtonText: "No, cancel purchase"
}, function() {
//Confirm purchase
//console.log('purchased megaphone');
purchaseMega(msg,color);
//window.location.href = linkURL;
});
},
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();
})();