// ==UserScript==
// @name Kokuros Utilities Mod (Status :✔️:)
// @description Krunker.io Mod
// @version 1.0.3
// @author Kokuro Hacks ✔️
// @include /^(https?:\/\/)?(www\.)?(.+)krunker\.io(|\/|\/\?.+)$/
// @grant none
// @run-at document-start
// @namespace https://greasyfork.org/users/313143
// ==/UserScript==
class Utilities {
constructor() {
this.findingNew = false;
this.deaths = 0;
this.lastSent = 0;
this.settings = null;
this.onLoad();
this.hexToRGB = hex => hex.replace(/^#?([a-f\d])([a-f\d])([a-f\d])$/i,
(m, r, g, b) => '#' + r + r + g + g + b + b)
.substring(1).match(/.{2}/g)
.map(x => parseInt(x, 16));
}
createSettings() {
inviteButton.insertAdjacentHTML("afterend", '\n<div class="button small" onmouseenter="playTick()" onclick="showWindow(window.windows.length-1);">Join</div>');
subLogoButtons.insertAdjacentHTML("beforeend", '<div class="button small" onmouseenter="playTick()" onclick="showWindow(window.windows.length);">Kokuros Utilities</div>');
const selectStyle = `border: none; background: #eee; padding: 4px; float: right; margin-left: 10px;`;
const textInputStyle = `border: none; background: #eee; padding: 6px; padding-bottom: 6px; float: right;`;
this.settings = {
showLeaderboard: {
name: "Show Leaderboard",
pre: "<div class='setHed'><center>Subscribe to Krunker News</center></div><div class='setHed'>Render</div><hr>",
val: true,
html: _ => {
return `<label class='switch'><input type='checkbox' onclick='window.utilities.setSetting("showLeaderboard", this.checked)' ${this.settings.showLeaderboard.val ? "checked" : ""}><span class='slider'></span></label>`;
},
set: val => {
leaderDisplay.style.display = val ? "block" : "none";
}
},
autoFindNew: {
name: "New Lobby Finder",
pre: "<br><div class='setHed'>Features</div><hr>",
val: false,
html: _ => {
return `<label class='switch'><input type='checkbox' onclick='window.utilities.setSetting("autoFindNew", this.checked)' ${this.settings.autoFindNew.val ? "checked" : ""}><span class='slider'></span></label>`;
}
},
matchEndMessage: {
name: "Match End Message",
val: '',
html: _ => {
return `<input type='text' id='matchEndMessage' placeholder='Match End Message' name='text' style='${textInputStyle}' value='${this.settings.matchEndMessage.val}' oninput='window.utilities.setSetting("matchEndMessage", this.value)' style='float:right;margin-top:5px'/>`
}
},
deathCounter: {
name: "Death Counter",
val: false,
html: _ => {
return `<label class='switch'><input type='checkbox' onclick='window.utilities.setSetting("deathCounter", this.checked)' ${this.settings.deathCounter.val ? "checked" : ""}><span class='slider'></span></label>`;
},
set: val => {
document.getElementById('deathCounter').style.display = val ? "inline-block" : "none";
}
},
forceChallenge: {
name: "Force Challenge Mode",
val: false,
html: _ => {
return `<label class='switch'><input type='checkbox' onclick='window.utilities.setSetting("forceChallenge", this.checked)' ${this.settings.forceChallenge.val ? "checked" : ""}><span class='slider'></span></label>`;
},
set: val => {
if (val && !challButton.lastElementChild.firstChild.checked) challButton.lastElementChild.firstChild.click();
}
},
autoMod: {
name: "Auto Load Mod",
val: '',
html: _ => {
return `<input type='text' id='autoMod' placeholder='Mod URL' name='text' style='${textInputStyle}' value='${this.settings.autoMod.val}' oninput='window.utilities.setSetting("autoMod", this.value)' style='float:right;margin-top:5px'/>`
},
set: val => {
if (val.length > 1) loadModPack(val, true);
}
},
customCrosshair: {
name: "Display",
pre: "<br><div class='setHed'>Crosshair</div><hr>",
val: 0,
html: _ => {
return `<select style='${selectStyle}' onchange="window.utilities.setSetting('customCrosshair', this.value)">
<option value="0"${this.settings.customCrosshair.val == 0 ? " selected" : ""}>Normal</option>
<option value="1"${this.settings.customCrosshair.val == 1 ? " selected" : ""}>Custom</option>
<option value="2"${this.settings.customCrosshair.val == 2 ? " selected" : ""}>Custom & Normal</option>
</select>`
},
set: val => {
let options = ['customCrosshairShape', 'customCrosshairAlwaysShow', 'customCrosshairShadow', 'customCrosshairColor', 'customCrosshairLength', 'customCrosshairThickness'];
for (let opt of options) {
this.settings[opt].hide = val == 0;
let doc = document.getElementById(opt + '_div');
if (doc) doc.style.display = val == 0 ? 'none' : 'block';
}
this.settings.customCrosshairShape.set(this.settings.customCrosshairShape.val);
}
},
customCrosshairShape: {
name: "Style",
val: 0,
hide: true,
html: _ => {
return `<select style='${selectStyle}' onchange="window.utilities.setSetting('customCrosshairShape', this.value)">
<option value="0"${this.settings.customCrosshairShape.val == 0 ? " selected" : ""}>Cross</option>
<option value="1"${this.settings.customCrosshairShape.val == 1 ? " selected" : ""}>Hollow Circle</option>
<option value="2"${this.settings.customCrosshairShape.val == 2 ? " selected" : ""}>Solid Circle</option>
<option value="3"${this.settings.customCrosshairShape.val == 3 ? " selected" : ""}>Image</option>
<option value="4"${this.settings.customCrosshairShape.val == 4 ? " selected" : ""}>Hollow Square</option>
<option value="5"${this.settings.customCrosshairShape.val == 5 ? " selected" : ""}>Solid Square</option>
</select>`
},
set: val => {
this.settings.customCrosshairImage.hide = this.settings.customCrosshair.val == 0 ? true: !(val == 3);
this.settings.customCrosshairShadow.hide = this.settings.customCrosshair.val == 0 ? true: val == 3;
let doc = document.getElementById('customCrosshairImage_div');
if (doc) doc.style.display = this.settings.customCrosshairImage.hide ? 'none' : 'block';
doc = document.getElementById('customCrosshairShadow_div');
if (doc) doc.style.display = this.settings.customCrosshairShadow.hide ? 'none' : 'block';
}
},
customCrosshairImage: {
name: "Image",
val: '',
hide: true,
html: _ => {
return `<input type='url' id='customCrosshairImage' placeholder='Crosshair Image URL' name='text' style='${textInputStyle}' value='${this.settings.customCrosshairImage.val}' oninput='window.utilities.setSetting("customCrosshairImage", this.value)' style='float:right;margin-top:5px'/>`
}
},
customCrosshairAlwaysShow: {
name: "Always Show",
val: false,
hide: true,
html: _ => {
return `<label class='switch'><input type='checkbox' onclick='window.utilities.setSetting("customCrosshairAlwaysShow", this.checked)' ${this.settings.customCrosshairAlwaysShow.val ? "checked" : ""}><span class='slider'></span></label>`;
}
},
customCrosshairShadow: {
name: "Shadow",
val: '#000000',
hide: true,
html: _ => {
return `<input type='color' id='crosshairShadow' name='color' value='${this.settings.customCrosshairShadow.val}' oninput='window.utilities.setSetting("customCrosshairShadow", this.value)' style='float:right;margin-top:5px'/>`
}
},
customCrosshairColor: {
name: "Color",
val: "#ffffff",
hide: true,
html: _ => {
return `<input type='color' id='crosshairColor' name='color' value='${this.settings.customCrosshairColor.val}' oninput='window.utilities.setSetting("customCrosshairColor", this.value)' style='float:right;margin-top:5px'/>`
}
},
customCrosshairLength: {
name: "Length",
val: 16,
hide: true,
html: _ => {
return `<span class='sliderVal' id='slid_utilities_customCrosshairLength'>${this.settings.customCrosshairLength.val}</span><div class='slidecontainer'><input type='range' min='2' max='50' step='2' value='${this.settings.customCrosshairLength.val}' class='sliderM' oninput="window.utilities.setSetting('customCrosshairLength', this.value)"></div>`
}
},
customCrosshairThickness: {
name: "Thiccness lol (i like memes xD)",
val: 2,
hide: true,
html: _ => {
return `<span class='sliderVal' id='slid_utilities_customCrosshairThickness'>${this.settings.customCrosshairThickness.val}</span><div class='slidecontainer'><input type='range' min='2' max='20' step='2' value='${this.settings.customCrosshairThickness.val}' class='sliderM' oninput="window.utilities.setSetting('customCrosshairThickness', this.value)"></div>`
}
},
customADSDot: {
name: "ADSDot Image",
pre: "<br><div class='setHed'>Customization</div><hr>",
val: '',
html: _ => {
return `<input type='url' id='customADSDot' placeholder='ADSDot URL' name='url' style='${textInputStyle}' value='${this.settings.customADSDot.val}' oninput='window.utilities.setSetting("customADSDot", this.value)' style='float:right;margin-top:5px'/>`
}
},
customScope: {
name: "Scope Image",
val: '',
html: _ => {
return `<input type='url' id='customScope' placeholder='Scope Image URL' name='url' style='${textInputStyle}' value='${this.settings.customScope.val}' oninput='window.utilities.setSetting("customScope", this.value)' style='float:right;margin-top:5px'/>`
},
set: val => {
recticleImg.src = val.length > 1 ? val : location.origin + '/textures/recticle.png';
}
},
customScopeHideBoxes: {
name: "Hide Black Boxes",
val: false,
html: _ => {
return `<label class='switch'><input type='checkbox' onclick='window.utilities.setSetting("customScopeHideBoxes", this.checked)' ${this.settings.customScopeHideBoxes.val ? "checked" : ""}><span class='slider'></span></label>`;
},
set: val => {
[...document.querySelectorAll('.black')].forEach(el => el.style.display = val ? "none" : "block");
}
},
customAmmo: {
name: "Ammo Icon",
val: '',
html: _ => {
return `<input type='url' id='customAmmo' placeholder='Ammo Icon URL' name='url' style='${textInputStyle}' value='${this.settings.customAmmo.val}' oninput='window.utilities.setSetting("customAmmo", this.value)' style='float:right;margin-top:5px'/>`
},
set: val => {
ammoIcon.src = val.length > 1 ? val : location.origin + '/textures/ammo_0.png';
}
},
customFlashOverlay: {
name: "Muzzle Flash Image",
val: '',
html: _ => {
return `<input type='url' id='customFlashOverlay' placeholder='Muzzle Flash URL' name='url' style='${textInputStyle}' value='${this.settings.customFlashOverlay.val}' oninput='window.utilities.setSetting("customFlashOverlay", this.value)' style='float:right;margin-top:5px'/>`
},
set: val => {
flashOverlay.src = val.length > 1 ? val : location.origin + '/img/muzflash.png';
}
},
customKills: {
name: "Kill Icon",
val: '',
html: _ => {
return `<input type='url' id='customKills' placeholder='Kill Icon URL' name='url' style='${textInputStyle}' value='${this.settings.customKills.val}' oninput='window.utilities.setSetting("customKills", this.value)' style='float:right;margin-top:5px'/>`
},
set: val => {
killsIcon.src = val.length > 1 ? val : location.origin + '/img/skull.png';
}
},
customDeaths: {
name: "Death Icon",
val: '',
html: _ => {
return `<input type='url' id='customDeaths' placeholder='Death Icon URL' name='url' style='${textInputStyle}' value='${this.settings.customDeaths.val}' oninput='window.utilities.setSetting("customDeaths", this.value)' style='float:right;margin-top:5px'/>`
},
set: val => {
deathIcon.src = val.length > 1 ? val : 'https://i.imgur.com/wTEFQRS.png';
}
},
customBlood: {
name: "Death Overlay",
val: '',
html: _ => {
return `<input type='url' id='customBlood' placeholder='Death Overlay URL' name='url' style='${textInputStyle}' value='${this.settings.customBlood.val}' oninput='window.utilities.setSetting("customBlood", this.value)' style='float:right;margin-top:5px'/>`
},
set: val => {
bloodDisplay.src = val.length > 1 ? val : location.origin + '/img/blood.png';
}
},
customTimer: {
name: "Timer Icon",
val: '',
html: _ => {
return `<input type='url' id='customTimer' placeholder='Timer Icon URL' name='url' style='${textInputStyle}' value='${this.settings.customTimer.val}' oninput='window.utilities.setSetting("customTimer", this.value)' style='float:right;margin-top:5px'/>`
},
set: val => {
timerIcon.src = val.length > 1 ? val : location.origin + '/img/timer.png';
}
}
};
window.windows.push({
header: "Join",
gen: _ => {
return `<input id='gameURL' type='text' placeholder='Enter Game URL/Code' class='accountInput' style='margin-top:0' value=''></input>
<div class='accountButton' onclick='window.utilities.joinGame()', style='width:100%'>Join</div>`;
}
});
window.windows.push({
header: "Kokuro Utilities",
gen: _ => {
var tmpHTML = "";
for (var key in window.utilities.settings) {
if (window.utilities.settings[key].noShow) continue;
if (window.utilities.settings[key].pre) tmpHTML += window.utilities.settings[key].pre;
tmpHTML += "<div class='settName' id='" + key + "_div' style='display:" + (window.utilities.settings[key].hide ? 'none' : 'block') +"'>" + window.utilities.settings[key].name +
" " + window.utilities.settings[key].html() + "</div>";
}
tmpHTML += "<br><a onclick='window.utilities.resetSettings()' class='menuLink'>Reset Settings</a>";
return tmpHTML;
}
});
this.setupSettings();
}
setupSettings() {
for (const key in this.settings) {
var tmpVal = getSavedVal(`kro_set_utilities_${key}`);
this.settings[key].val = (tmpVal!== null)?tmpVal:this.settings[key].val;
if (this.settings[key].val == "false") this.settings[key].val = false;
if (this.settings[key].set) this.settings[key].set(this.settings[key].val, true);
}
}
joinGame() {
let code = gameURL.value || '';
if (code.match(/^(https?:\/\/)?(www\.)?(.+)krunker\.io(|\/|\/\?(server|party|game)=.+)$/)) {
location = code;
} else if (code.match(/^([A-Z]+):(\w+)$/)) {
location = location.origin + "/?game=" + code;
}
}
createDeathCounter() {
let deathCounter = document.createElement('div');
deathCounter.id = 'deathCounter';
deathCounter.style.cssText = `margin-left: 10px;
margin-top: 20px;
background-color: rgba(0, 0, 0, 0.2);
padding: 10px;
display: inline-block;
font-size: 26px;
padding-right: 20px;
padding-left: 14px;
display: none`;
let deathIcon = document.createElement('img');
deathIcon.id = 'deathIcon';
deathIcon.src = 'https://i.imgur.com/wTEFQRS.png';
deathIcon.style.cssText = `width: 38px;
height: 38px;
padding-right: 10px;
image-rendering: pixelated;
image-rendering: -moz-crisp-edges;
image-rendering: crisp-edges;`;
deathCounter.appendChild(deathIcon);
let deathsVal = document.createElement('span');
deathsVal.id = 'deathsVal';
deathsVal.style.color = 'rgba(255, 255, 255, 0.7)';
deathsVal.innerHTML = '0';
deathCounter.appendChild(deathsVal);
topRight.appendChild(deathCounter);
}
createCrosshair() {
let div = document.createElement('div');
div.id = 'custCross';
div.style.display = 'none';
let crossS = document.createElement('div');
crossS.id = 'crossS';
crossS.style.cssText = `
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
display: none;`;
div.appendChild(crossS);
let crossH = document.createElement('div');
crossH.id = 'crossH';
crossH.style.cssText = crossS.style.cssText;
div.appendChild(crossH);
let crossV = document.createElement('div');
crossV.id = 'crossV';
crossV.style.cssText = crossS.style.cssText;
div.appendChild(crossV);
let crossCirc = document.createElement('div');
crossCirc.id = 'crossCirc';
crossCirc.style.cssText = crossS.style.cssText;
div.appendChild(crossCirc);
let crossImg = document.createElement('div');
crossImg.id = 'crossImg';
crossImg.style.cssText = `
position: fixed;
top: 0;
left: 0;
margin: auto;
width: 100%;
height: 100%;
background-repeat: no-repeat;
background-position: center;
display: none`;
div.appendChild(crossImg);
inGameUI.appendChild(div);
}
updateCrosshair() {
if (this.settings.customCrosshair.val == 0 || !this.settings.customCrosshairAlwaysShow.val && (aimDot.style.opacity != "0" || aimRecticle.style.opacity != "0")) return custCross.style.display = 'none';
custCross.style.display = 'block';
let shadow = this.hexToRGB(this.settings.customCrosshairShadow.val);
let thickness = parseInt(this.settings.customCrosshairThickness.val);
let length = parseInt(this.settings.customCrosshairLength.val);
let color = this.settings.customCrosshairColor.val;
let shape = parseInt(this.settings.customCrosshairShape.val);
if (shape == 0) { // CROSS
crossV.style.display = 'block';
crossH.style.display = 'block';
crossS.style.display = 'block';
crossCirc.style.display = 'none';
crossImg.style.display = 'none';
crossV.style.height = `${length * 2}px`;
crossV.style.width = `${thickness}px`;
crossV.style.backgroundColor = `${color}`;
crossH.style.height = `${thickness}px`;
crossH.style.width = `${length * 2}px`;
crossH.style.backgroundColor = `${color}`;
crossH.style.boxShadow = `0px 0px 5px 1px rgba(${shadow.join(',')},0.75)`;
crossS.style.height = `${length * 2}px`;
crossS.style.width = `${thickness}px`;
crossS.style.backgroundColor = `${color}`;
crossS.style.boxShadow = `0px 0px 5px 1px rgba(${shadow.join(',')},0.75)`;
} else if (shape == 3) { // IMAGE
crossV.style.display = 'none';
crossH.style.display = 'none';
crossS.style.display = 'none';
crossCirc.style.display = 'none';
crossImg.style.display = 'block';
if (crossImg.style.backgroundImage != this.settings.customCrosshairImage.val) {
crossImg.style.backgroundImage = `url(${this.settings.customCrosshairImage.val})`;
}
} else { // HOLLOW CIRCLE | FILLED CIRCLE
crossV.style.display = 'none';
crossH.style.display = 'none';
crossS.style.display = 'none';
crossCirc.style.display = 'block';
crossImg.style.display = 'none';
crossCirc.style.height = `${length * 2}px`;
crossCirc.style.width = `${length * 2}px`;
crossCirc.style.backgroundColor = shape == 2 || shape == 5 ? `${color}` : ``;
crossCirc.style.border = shape == 2 || shape == 5 ? `` : `${thickness}px solid ${color}`;
crossCirc.style.boxShadow = `0px 0px 5px 1px rgba(${shadow.join(',')},0.75)`;
crossCirc.style.borderRadius = shape > 3 ? '':'50%';
}
}
createObservers() {
this.newObserver(crosshair, 'style', (target) => {
if (this.settings.customCrosshair.val == 0) return;
crosshair.style.opacity = this.crosshairOpacity(crosshair.style.opacity);
}, false);
this.newObserver(aimDot, 'src', (target) => {
if (this.settings.customADSDot.val.length > 1) {
if (this.settings.customADSDot.val != target.src) {
target.src = this.settings.customADSDot.val;
}
}
});
this.newObserver(killCardHolder, 'style', () => {
this.deaths++;
deathsVal.innerHTML = this.deaths;
});
this.newObserver(victorySub, 'src', () => {
this.deaths = 0;
deathsVal.innerHTML = this.deaths;
if (this.settings.matchEndMessage.val.length) {
if (Date.now() - this.lastSent > 20) {
this.sendMessage(this.settings.matchEndMessage.val);
this.lastSent = Date.now();
}
}
});
this.newObserver(instructionHolder, 'style', (target) => {
if (this.settings.autoFindNew.val) {
if (target.innerText.includes('Try seeking a new game') &&
!target.innerText.includes('Subscribe to Krunker News')) {
location = document.location.origin;
}
}
});
}
newObserver(elm, check, callback, onshow = true) {
return new MutationObserver((mutationsList, observer) => {
if (check == 'src' || onshow && mutationsList[0].target.style.display == 'block' || !onshow) {
callback(mutationsList[0].target);
}
}).observe(elm, check == 'childList' ? {childList: true} : {attributes: true, attributeFilter: [check]});
}
sendMessage(msg) {
chatInput.value = msg;
chatInput.focus()
window.pressButton(13);
chatInput.blur();
}
createWatermark() {
const el = document.createElement("div");
el.id = "watermark";
el.style.position = "absolute";
el.style.color = "rgba(50,205,50, 0.3)";
el.style.bottom = "0";
el.style.left = "20px";
el.style.fontSize = "6pt";
el.innerHTML = "Subscribe to Krunker News";
gameUI.appendChild(el);
}
crosshairOpacity(val) {
return parseInt(this.settings.customCrosshair.val) == 1 ? 0 : val;
}
render() {
this.updateCrosshair();
window.requestAnimationFrame(_ => this.render());
}
resetSettings() {
if (confirm("Are you sure you want to reset all your utilties settings? This will also refresh the page")) {
Object.keys(localStorage).filter(x=>x.includes("kro_set_utilities_")).forEach(x => localStorage.removeItem(x));
location.reload();
}
}
setSetting(t, e) {
this.settings[t].val = e;
saveVal(`kro_set_utilities_${t}`, e);
if (document.getElementById(`slid_utilities_${t}`)) document.getElementById(`slid_utilities_${t}`).innerHTML = e;
if (this.settings[t].set) this.settings[t].set(e);
}
keyDown(event) {
if (document.activeElement.tagName == "INPUT") return;
switch(event.key){
case '`':
if (event.ctrlKey || event.shiftKey) return;
document.exitPointerLock = document.exitPointerLock || document.mozExitPointerLock;
document.exitPointerLock();
window.showWindow(window.windows.length);
break;
}
}
onLoad() {
this.createCrosshair();
this.createWatermark();
this.createDeathCounter();;
this.createSettings();
this.createObservers();
window.addEventListener("keydown", event => this.keyDown(event));
window.requestAnimationFrame(_ => this.render());
}
}
document.addEventListener('DOMContentLoaded', _ => {
window.utilities = new Utilities();
}, false);