Bonk Host

Makes hosting rooms in bonk.io better

当前为 2022-06-21 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Bonk Host
// @version      1.12
// @author       Salama
// @description  Makes hosting rooms in bonk.io better
// @match        https://bonk.io/gameframe-release.html
// @run-at       document-start
// @grant        none
// @supportURL   https://discord.gg/Dj6usq7ww3
// @namespace    https://greasyfork.org/users/824888
// ==/UserScript==

// for use as a userscript ensure you have Excigma's code injector userscript
// https://greasyfork.org/en/scripts/433861-code-injector-bonk-io

let injector = (str) => {
	let newStr = str;
window.bonkHost = {};
window.bonkHost.playerManagement = {};
window.bonkHost.freejoin = false;
window.bonkHost.playerCount = 0;
window.bonkHost.playerNames = [];
window.bonkHost.scores = [];
window.bonkHost.startGameFunction = () => {return;};

window.bonkCommands = window.bonkCommands.concat(["/kick", "/mute", "/unmute", "/lock", "/unlock", "/balance", "/fav", "/unfav", "/curate", "/curateyes", "/curateno", "/hhelp", "/balanceall", "/start", "/freejoin"]);

let hostPlayerMenuCSS = document.createElement('style');
hostPlayerMenuCSS.innerHTML = `
#hostPlayerMenu {
	background-color: #cfd8cd;
	width: calc(35.2vw - 400px);
	min-width: 154px;
	max-width: 260px;
	height: 551px;
	position: absolute;
	left: 1%;
	top: 60px;
	border-radius: 7px;
	display: none;
    transition: ease-in-out 100ms;
}

#hostPlayerMenuCollapse {
    position: absolute;
    left: 3px;
    top: 3px;
    width: 26px;
    height: 26px;
    border-radius: 2px;
    text-transform: full-width;
    visibility: visible;
}

#hostPlayerMenuControls {
    position:absolute;
    bottom:0;
    width:100%;
}`;
document.getElementsByTagName('head')[0].appendChild(hostPlayerMenuCSS);

let hostPlayerMenu = document.createElement('div');
document.getElementById('pagecontainer').appendChild(hostPlayerMenu);
hostPlayerMenu.outerHTML = `
<div class="windowShadow" id="hostPlayerMenu">
	<div class="newbonklobby_boxtop newbonklobby_boxtop_classic" style="background-color: #009688;">
		<div onclick="window.bonkHost.playerManagement.collapse();" id="hostPlayerMenuCollapse" class="newbonklobby_settings_button brownButton brownButton_classic buttonShadow">-</div>
		Player List</div>
	<div id="hostPlayerMenuBox" class="newbonklobby_elementcontainer"></div>
	<div id="hostPlayerMenuControls">
		<table>
			<tbody>
				<tr style="background-color: rgba(58, 58, 58, 0.07);">
					<td style="padding-left: 10px;" class="mapeditor_rightbox_table">
						Teamlock
					</td>
					<td>
						<input type="checkbox" id="hostPlayerMenuTeamlock">
					</td>
				</tr>
				<tr style="background-color: rgba(58, 58, 58, 0.07);">
					<td style="padding-left: 10px;" class="mapeditor_rightbox_table">
						Freejoin
					</td>
					<td>
						<input type="checkbox" id="hostPlayerMenuFreejoin">
					</td>
				</tr>
				<tr style="background-color: rgba(58, 58, 58, 0.07);">
					<td style="padding-left: 10px;" class="mapeditor_rightbox_table">
						Keep scores
					</td>
					<td>
						<input type="checkbox" id="hostPlayerMenuKeepScores">
					</td>
				</tr>
				<tr style="background-color: rgba(58, 58, 58, 0.07);">
					<td style="padding-left: 10px;" class="mapeditor_rightbox_table">
						Keep positions
					</td>
					<td>
						<input type="checkbox" id="hostPlayerMenuKeepPositions">
					</td>
				</tr>
			</tbody>
		</table>
		<div class="newbonklobby_settings_button brownButton brownButton_classic buttonShadow" style="width:100%;" id="hostPlayerMenuRestartButton">
			RESTART GAME
		</div>
	</div>
</div>
<div id="selectionWheel" style="width: 150px; height: 150px; position: absolute; left: 1061px; top: 169px; pointer-events: none; display: none;">
	<svg width="150" height="150" viewBox="0 0 26.458 26.458"><g><path d="M22.009-13.227a8.78 8.78 0 0 1-13.17 7.605 8.78 8.78 0 0 1-4.39-7.605" transform="rotate(90)" stroke="#fff" style="stroke-linejoin: round; stroke-width: 9; fill: none; opacity: 0.5; stroke: rgb(121, 85, 72);"></path><text class="brownButton_classic" style="
		text-anchor: middle;
		font-family: 'futurept_b1';
		font-size: 3.17496;
		transform: scale(1, 1);
		fill: #fff;
	"><tspan x="4.5" y="14.4">FFA</tspan></text>
	</g><g style="transform: translateX(50%);transform-origin: 100% 0px;"><path d="M22.009-13.227a8.78 8.78 0 0 1-13.17 7.605 8.78 8.78 0 0 1-4.39-7.605" transform="rotate(90)" stroke="#fff" style="stroke-linejoin: round; stroke-width: 9; fill: none; opacity: 0.5; transform: rotate(-90deg); transform-origin: 75% 25%; stroke: rgb(121, 85, 72);"></path><text style="
		text-anchor: middle;
		font-family: 'futurept_b1';
		font-size: 3.17496;
		transform: scale(1, 1);
		fill: #fff;
	"><tspan x="8.8" y="14.4">SPEC</tspan></text></g></svg>
</div>

<div id="selectionWheelTeams" style="width: 150px; height: 150px; position: absolute; left: 588px; top: 181px; pointer-events: none; display: none;">
	<svg width="150" height="150" viewBox="0 0 26.458 26.458" style="
"><g stroke-linejoin="round" stroke-width="9" stroke="#fff" style="transform: rotate(180deg);transform-origin: 50% 0%;"><path d="M6.126-8.066c-2.236-3.078-2.236-7.246 0-10.323" style="opacity: 0.5; stroke: rgb(121, 85, 72);"></path><path d="M6.126-18.39a8.78 8.78 0 0 1 9.816-3.19" style="stroke: rgb(255, 235, 59); opacity: 1;"></path><path d="M15.942-21.58a8.78 8.78 0 0 1 6.067 8.352" style="stroke: rgb(76, 175, 80); opacity: 0.5;"></path><path d="M22.009-13.228a8.78 8.78 0 0 1-6.067 8.352" style="stroke: rgb(33, 150, 243); opacity: 0.5;"></path><path d="M15.942-4.876a8.78 8.78 0 0 1-9.816-3.19" style="stroke: rgb(244, 67, 54); opacity: 0.5;"></path></g><text font-size="6" fill="#000" style="
		text-anchor: middle;
		font-family: 'futurept_b1';
		font-size: 3.17496;
		fill: #fff;
	"><tspan x="22" y="14.4">SPEC</tspan></text><text font-size="6" fill="#000" style="
		text-anchor: middle;
		font-family: 'futurept_b1';
		font-size: 3.17496;
		fill: #fff;
	"><tspan x="16.75" y="22.5">YELLOW</tspan></text><text font-size="6" fill="#000" style="
		text-anchor: middle;
		font-family: 'futurept_b1';
		font-size: 3.17496;
		fill: #fff;
	"><tspan x="16.5" y="6">RED</tspan></text><text font-size="6" fill="#000" style="
		text-anchor: middle;
		font-family: 'futurept_b1';
		font-size: 3.17496;
		fill: #fff;
	"><tspan x="6" y="9.5">BLUE</tspan></text><text font-size="6" fill="#000" style="
		text-anchor: middle;
		font-family: 'futurept_b1';
		font-size: 3.17496;
		fill: #fff;
	"><tspan x="6" y="19.5">GREEN</tspan></text></svg>
</div>`;

let CUSTOM_COMMANDS = `
if(I8H[5][0] == "/hhelp") {
	u6H[29].showStatusMessage("/balance * -100 to 100 -- Balances everyone","#cc3333",false);
	u6H[29].showStatusMessage("/balanceall -100 to 100 -- Balances everyone","#cc3333",false);
	u6H[29].showStatusMessage("/start -- Starts the game","#cc3333",false);
	u6H[29].showStatusMessage("/freejoin on/off -- Lets people join during the game","#cc3333",false);
}
else if(I8H[5][0] == "/start" && !u6H[64]) {
    window.bonkHost.startGame();
}
else if(I8H[5][0] == "/freejoin" && !u6H[64]) {
    if(["true", "on", "yes", "enable"].includes(I8H[5][1])) {
        window.bonkHost.freejoin = true;
	    F5S("* Freejoin on","#cc3333",true);
    }
    else if(["false", "off", "no", "disable"].includes(I8H[5][1])) {
        window.bonkHost.freejoin = false;
	    F5S("* Freejoin off","#cc3333",true);
    }
    else if(I8H[5].length == 1) {
        window.bonkHost.freejoin = !window.bonkHost.freejoin;
	    F5S("* Freejoin " + (window.bonkHost.freejoin ? "on" : "off"),"#cc3333",true);
    }
    document.getElementById('hostPlayerMenuFreejoin').checked = window.bonkHost.freejoin;
}
`;

let BALANCE_ALL_MESSAGE = `
if(I8H[67] == -2) {
	u6H[29].showStatusMessage("* " + "Everyone" + " has had their buff/nerf set to " + I8H[32], "#cc3333", false);
}
else if(I8H[32] == 0)
`;

let BALANCE_SELECTION = `

u6H[36].bal[I8H[17]] = I8H[32];
u6H[11].sendBalance(I8H[17], I8H[32]);
if (u6H[29]) {
	u6H[29].updatePlayers();
}
I8H[67]=-2;
if (u6H[44][I8H[17]].userName.toLowerCase() == I8H[7].toLowerCase()) {
    I8H[67] = I8H[17];
    break;
}
`;

let SUGGESTION_MODE_BUTTON = `
let space = document.createElement("span");
space.classList.add("newbonklobby_mapsuggest_high");
space.appendChild(document.createTextNode(" "));

let smb = document.createElement("span");
smb.classList.add("newbonklobby_mapsuggest_high");
smb.classList.add("newbonklobby_chat_link");
smb.style.color="#ff0000";
v2k[79].setButtonSounds([smb]);

smb.onclick = () => {
	d9G[73].onclick();
	window.bonkSetMode(w3G[2][d9G[73].suggestID].m.mo);
};
`;

let APPEND_SUGGESTION_MODE_BUTTON = `
if(!!v2k[10].modes[w3G[2][d9G[73].suggestID].m.mo]) {
	d9G[8].appendChild(space);
	smb.appendChild(document.createTextNode("[" + v2k[10].modes[w3G[2][d9G[73].suggestID].m.mo].lobbyName + "]"));
	d9G[8].appendChild(smb);
}
`;

let modeStuff = newStr.match(
    new RegExp(
        "(var .{2,4}=\\[arguments\\];.{2,4}\\[\\d{1,2}\\]=.{2,5};).{1,300}\
\\+\\+;\
if.{5,60}=0;\\}\
(.{5,50}=.{5,50})\
\\[.{2,4}\\[\\d{1,4}\\]\\];\
(.{5,200}=true.{5,200}\\(\\);)\
\\}\\}"
    )
);
// 1 is var m7p = [arguments]; m7p[4] = y3uu;
// 2 is G7p[0][2]["mo"] = P1R[43]["lobbyModes"]
// 3 is code that updates the mode
let modeVar =
    modeStuff[2].split("=")[0].match(/.{2,4}\[\d{1,2}\]\[\d{1,2}\]/g)[0] +
    `["mo"]`;
let modesObject =
    modeStuff[2].split("=")[1].match(/.{2,4}\[\d{2,4}\]/g)[0] + `["modes"]`;

window.modeDropdownCreated = false;
window.createModeDropdown = () => {
    if (window.modeDropdownCreated) return;
    window.modeDropdownCreated = true;
    const dropdown = document.createElement("div");
    dropdown.classList = "dropdown-container";
    const mds = dropdown.style;
    mds.color = "#ffffff";
    mds.position = "absolute";
    mds.right = "15px";
    mds.bottom = "55px";
    mds.width = "116px";
    mds.height = "30px";
    mds.display = "flex";
    mds.textAlign = "center";
    mds.flexDirection = "column-reverse";

    document.getElementById("newbonklobby_modebutton").remove();
    let title = document.createElement("div");
    title.classList = "dropdown-title dropdown_classic";
    title.innerText = "MODE";
    title.style.fontSize = "18px";
    title.id = "newbonklobby_modebutton";
    title.style.position = "unset";
    dropdown.appendChild(title);

    const options = [];
    let dropdownOpen = false;

    function toggleVisibility(e) {
        dropdownOpen = !dropdownOpen;
        for (const o of options) {
            o.style.visibility = dropdownOpen ? "" : "hidden";
        }
        e.stopImmediatePropagation();
    }

    for (const mode of Object.keys(window.bonkModesObject)) {
        const option = document.createElement("div");
        option.classList = "dropdown-option dropdown_classic";
        option.style.display = "block";
        option.style.visibility = "hidden";
        option.style.fontSize = "15px";
        option.innerText = window.bonkModesObject[mode].lobbyName;
        option.onclick = (e) => {
            window.bonkSetMode(mode);
            toggleVisibility(e);
        };
        options.push(option);
        dropdown.appendChild(option);
    }

    title.addEventListener("click", toggleVisibility);

    document.getElementById("newbonklobby_settingsbox").appendChild(dropdown);
};

let PLAYER_CLICK_MENU = `
if(playerEntry) {
    playerEntry.parentNode.appendChild(m9G[6]);
}
else` + " ";

let KEEP_SCORES = `
if(window.bonkHost.scores.length > 0 && document.getElementById('hostPlayerMenuKeepScores').checked) {
    k7k[1].scores = window.bonkHost.scores;
}
else` + " ";

let SET_STATE = `
document.getElementById("hostPlayerMenuKeepPositions").parentNode.parentNode.style.display = (u6H[36].map.s.re ? "" : "none");
if(I8yy.bonkHost.state && window.bonkHost.keepState && u6H[36].map.s.re) {
    for(let i = 0; i < I8yy.bonkHost.state.discs.length; i++) {
        if(I8yy.bonkHost.state.discs[i] != undefined) {
            W6H[2].discs[i] = I8yy.bonkHost.state.discs[i];
            if(u6H[36].mo=='sp') {
                W6H[2].discs[i].a1a -= 2*30*3;
            }
        }
    }
    for(let i = 0; i < I8yy.bonkHost.state.discDeaths.length; i++) {
        if(I8yy.bonkHost.state.discDeaths[i] != undefined) {
            W6H[2].discDeaths[i] = I8yy.bonkHost.state.discDeaths[i];
        }
    }
    W6H[2].physics=I8yy.bonkHost.state.physics;
    W6H[2].seed=I8yy.bonkHost.state.seed;
    W6H[2].rc=I8yy.bonkHost.state.rc;
    W6H[2].ftu=60;
    W6H[2].shk=I8yy.bonkHost.state.shk;
    W6H[2].projectiles=I8yy.bonkHost.state.projectiles;
    W6H[2].capZones=I8yy.bonkHost.state.capZones;
    window.bonkHost.keepState=false;
}W6H[2][
`;

let FREEJOIN = `
if(window.bonkHost.freejoin||u6H[64]) {
    let team = u6H[44].filter(e => {return e != null && u6H[44].indexOf(e) !== s6H[0][0] && e.team != 0}).map(e => {return e.team}).reduce((a, b) => {return a == b ? a : false});
    team = team ? team : 0;
    u6H[44][s6H[0][0]].team = team;
    s6H[0][4] = team;
`;

document.getElementById('hostPlayerMenuFreejoin').addEventListener('change', (e) => {
    window.bonkHost.freejoin = e.target.checked;
});

document.getElementById('hostPlayerMenuTeamlock').addEventListener('change', () => {
    document.getElementById('newbonklobby_teamlockbutton').onclick();
});

window.bonkHost.playerManagement.addPlayer = (playerEntry, info) => {
    while(window.bonkHost.playerManagement.getPlayer(playerEntry)) {
        window.bonkHost.playerManagement.removePlayer(playerEntry);
    }
    let newPlayerEntry = playerEntry.cloneNode(true);
    newPlayerEntry.classList.remove('newbonklobby_playerentry_half');
    newPlayerEntry.getElementsByClassName("newbonklobby_playerentry_ping")[0].remove();
    newPlayerEntry.getElementsByClassName("newbonklobby_playerentry_host")[0].remove();
    newPlayerEntry.onclick = playerEntry.onclick;
    newPlayerEntry.onmouseenter = playerEntry.onmouseenter;
    if(
        info.team === 0 ||
        (document.getElementById("newbonklobby_teams_middletext").textContent === "TEAMS ON" && info.team === 1) ||
        (document.getElementById("newbonklobby_teams_middletext").textContent === "TEAMS OFF" && info.team > 1) ||
        (
            !window.bonkHost.freejoin &&
            !window.bonkHost.menuFunctions.visible &&
            I8yy.bonkHost.state.discs[window.bonkHost.players.findIndex(i => {return i && i.userName === newPlayerEntry.children[1].textContent})] == undefined &&
            I8yy.bonkHost.state.discDeaths.findIndex(i => {return i.i === window.bonkHost.players.findIndex(i => {return i && i.userName === newPlayerEntry.children[1].textContent})})
        )
    ) {
        newPlayerEntry.style.filter = "opacity(0.4)";
    }
    hostPlayerMenuBox.appendChild(newPlayerEntry);
    if(!window.bonkHost.playerNames.includes(newPlayerEntry.children[1].textContent)) {
        window.bonkHost.playerNames.push(newPlayerEntry.children[1].textContent);
    }
}

window.bonkHost.redrawSkin = (skinElement) => {
    if(!skinElement.parentNode.classList.contains("newbonklobby_playerentry")) return;
    let playerElement = [...document.getElementById("hostPlayerMenuBox").children].filter(e => {return e.children[1] && e.children[1].textContent === skinElement.parentNode.getElementsByClassName("newbonklobby_playerentry_name")[0].textContent})[0];
    if(!playerElement) return;
    playerElement.removeChild(playerElement.getElementsByClassName("newbonklobby_playerentry_avatar")[0]);
    playerElement.insertBefore(skinElement.cloneNode(true), playerElement.getElementsByClassName("newbonklobby_playerentry_name")[0]);
}

window.bonkHost.playerManagement.removePlayer = (playerEntry) => {
    if((foundPlayerEntry = window.bonkHost.playerManagement.getPlayer(playerEntry)) && foundPlayerEntry) {
        hostPlayerMenuBox.removeChild(foundPlayerEntry);
        if(window.bonkHost.playerNames.includes(foundPlayerEntry.children[1].textContent)) {
            window.bonkHost.playerNames.splice(window.bonkHost.playerNames.indexOf(foundPlayerEntry.children[1].textContent), 1);
        }
    }
}

window.bonkHost.playerManagement.show = () => {
    if(window.bonkHost.menuFunctions.visible) return;
    if(parent.document.getElementById('adboxverticalleftCurse') != null)
        parent.document.getElementById('adboxverticalleftCurse').style.display = "none";
    document.getElementById('hostPlayerMenu').style.display = "unset";
}

window.bonkHost.playerManagement.hide = () => {
    document.getElementById('hostPlayerMenu').style.display = "none";
    if(parent.document.getElementById('adboxverticalleftCurse') != null)
        parent.document.getElementById('adboxverticalleftCurse').style.removeProperty("display");
}

window.bonkHost.playerManagement.collapse = () => {
    if(document.getElementById('hostPlayerMenu').style.visibility != "hidden") {
        document.getElementById('hostPlayerMenuControls').style.display = "none";
        document.getElementById('hostPlayerMenuControls').visibility = "hidden";
        document.getElementById('hostPlayerMenu').style.minWidth = 0;
        document.getElementById('hostPlayerMenu').style.minHeight = 0;
        document.getElementById('hostPlayerMenu').style.width = 0;
        document.getElementById('hostPlayerMenu').style.height = 0;
        document.getElementById('hostPlayerMenu').style.visibility = "hidden";
        document.getElementById('hostPlayerMenuCollapse').textContent = "+";
    }
    else {
        document.getElementById('hostPlayerMenu').style.visibility = "visible";
        document.getElementById('hostPlayerMenu').style.removeProperty("min-width");
        document.getElementById('hostPlayerMenu').style.removeProperty("min-height");
        document.getElementById('hostPlayerMenu').style.removeProperty("width");
        document.getElementById('hostPlayerMenu').style.removeProperty("height");
        document.getElementById('hostPlayerMenu').style.visibility = "visible";
        document.getElementById('hostPlayerMenuCollapse').textContent = "-";
        setTimeout(() => {document.getElementById('hostPlayerMenuControls').style.removeProperty("display");}, 100);
    }
}

window.bonkHost.playerManagement.getPlayer = (playerEntry, exact = false) => {
    if (exact) {
        let child = [...hostPlayerMenuBox.children].indexOf(playerEntry);
        if(child) return hostPlayerMenuBox.children[child];
    }
    for(let child of hostPlayerMenuBox.children) {
        if(child.children[1].textContent == playerEntry.children[1].textContent) {
            return child;
        }
    }
    return false;
}

window.bonkHost.playerManagement.movePlayer = (playerID, playerCount, team) => {
    window.bonkHost.menuFunctions.visible = true;
    if(team > 0)
        window.bonkHost.bonkHandlers.hostHandlePlayerJoined(playerID, playerCount, team);
    else
        window.bonkHost.bonkHandlers.hostHandlePlayerLeft(playerID);
    window.bonkHost.menuFunctions.updatePlayers();
}

window.bonkHost.startGame = () => {
    window.bonkHost.keepState = document.getElementById("hostPlayerMenuKeepPositions").checked;
    window.bonkHost.startGameFunction();
}

document.getElementById('maploadwindowmapscontainer').addEventListener('DOMNodeInserted', e => {
    let mode = e.relatedNode.getElementsByClassName('maploadwindowtextmode')[0];
    if(mode === undefined) mode = e.relatedNode.getElementsByClassName('maploadwindowtextmode_picks')[0];
    if(mode.textContent !== "Any Mode") {
        mode.classList.add('brownButton');
        mode.classList.add('brownButton_classic');
        mode.classList.add('buttonShadow');
        mode.style.padding = "2px";
        mode.style.width = "90px";
    }
    mode.addEventListener("click", e => {
        if(!document.getElementById('newbonklobby_modebutton').classList.contains("brownButtonDisabled")) {
            window.bonkSetMode(Object.entries(window.bonkModesObject).filter(e => {return e[1].lobbyName === mode.textContent})[0][0]);
        }
    })
});

/*Autocomplete*/

document.getElementById('newbonklobby_chat_input').onkeydown = e => {
	if (e.keyCode === 9) {
		e.preventDefault();
		e.stopPropagation();
		let chatText = e.target.value.split(' ');
		let length = 0;
		for (let i = 0; i < chatText.length; i++) {
			length += chatText[i].length + 1;
			if (length <= e.target.selectionStart || chatText[i] === "")
				continue;
			let foundAutocompletes = [];
			let foundAutocompletesOffsets = [];
			for (let j = 0; j < window.bonkCommands.length; j++) {
				if (window.bonkCommands[j].toLowerCase().replace(/[.*+?^${}()|[\]\\]/g, '\\$&').match("^" + chatText[i].toLowerCase().replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))) {
					foundAutocompletes.push(window.bonkCommands[j]);
					foundAutocompletesOffsets.push(0);
				}
			}
			if (foundAutocompletes.length === 0) {
				for (let j = 0; j < window.bonkHost.playerNames.length; j++) {
					for (let k = i; k >= 0; k--) {
						if (window.bonkHost.playerNames[j].toLowerCase().replace(/[.*+?^${}()|[\]\\]/g, '\\$&').match("^" + chatText.slice(k, i + 1).join(" ").toLowerCase().replace(/"/g, "").replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))) {
							foundAutocompletes.push(window.bonkHost.playerNames[j]);
							foundAutocompletesOffsets.push(k);
						}
					}
				}
			}
			if (foundAutocompletes.length === 1) {
				let oldlen = chatText.slice(foundAutocompletesOffsets[0], i + 1).join(" ").length;
				for (let j = i; j > foundAutocompletesOffsets[0]; j--) {
					chatText.splice(j, 1);
				}
				if (chatText[0][0] === "/" && i > 0 && foundAutocompletes[0].includes(" ")) {
					chatText[foundAutocompletesOffsets[0]] = `"${foundAutocompletes[0]}" `;
				} else {
					chatText[foundAutocompletesOffsets[0]] = foundAutocompletes[0] + (foundAutocompletesOffsets[0] === (chatText.length - 1) && (chatText[0][0] === "/") && (chatText[foundAutocompletesOffsets[0] + 1] !== "") ? " " : "");
				}
				if(chatText[foundAutocompletesOffsets[0] + 1] === "") {
					chatText.splice(foundAutocompletesOffsets[0] + 1, 1);
				}
				e.target.value = chatText.join(' ');
				e.target.selectionStart = length - oldlen + chatText[foundAutocompletesOffsets[0]].length + ((foundAutocompletesOffsets[0] === chatText.length - 1) && (chatText[0][0] !== "/") ? 0 : 1);
				e.target.selectionEnd = length - oldlen + chatText[foundAutocompletesOffsets[0]].length + ((foundAutocompletesOffsets[0] === (chatText.length - 1)) && (chatText[0][0] !== "/") ? 1 : 0);
				return;
			} else if (foundAutocompletes.length > 1) {
				let maxAutocomplete = "";
				let char = "";
				for (let j = 0; j >= 0; j++) {
					maxAutocomplete += char;
					char = "";
					for (let k = 0; k < foundAutocompletes.length; k++) {
						if (char === "") char = foundAutocompletes[k][j];
						else if (foundAutocompletes[k][j] !== char) {
							j = -Infinity;
							break;
						}
					}
				}
                if(maxAutocomplete === "") return;
				let oldlen = chatText[i].length;
				let quotes = (chatText[0][0] === "/" && foundAutocompletes.some(r => r.includes(" ")));
				if (quotes) {
					chatText[i] = `"${maxAutocomplete}"`;
				} else {
					chatText[i] = maxAutocomplete;
				}
				e.target.value = chatText.join(' ');
				e.target.selectionStart = length - oldlen + chatText[i].length - quotes * 2;
				e.target.selectionEnd = length - oldlen + chatText[i].length - quotes * 2;
				return;
			}
		}
	}
}

(() => {
    let selectedPlayer = null;
    let start = [], end = [];
    const wheelSize = 150;
    let oldAngle = null;
    const innerWheelRadius = (wheelSize/26.458)/2*8.5;
    window.bonkHost.updatePlayers = () => {
        if(window.bonkHost.menuUsage.getLSID() !== window.bonkHost.menuUsage.hostID) return;
        [...document.getElementsByClassName("newbonklobby_playerentry")].filter(e => {return e.parentNode.id === "newbonklobby_playerbox_elementcontainer" || e.parentNode.id === "newbonklobby_specbox_elementcontainer" || e.parentNode.id === "hostPlayerMenuBox"}).forEach(e => {
            e.addEventListener("mousedown", mouse => {
                selectedPlayer = e;
                start = [mouse.clientY, mouse.clientX];
            });
        });
    }
    document.addEventListener("mousemove", mouse => {
        if(selectedPlayer) {
            document.body.style.pointerEvents = "none";
            let wheelType = (document.getElementById("newbonklobby_teams_middletext").textContent === "TEAMS OFF") ? "selectionWheel" : "selectionWheelTeams";
            document.getElementById(wheelType).style.display = "";
            document.getElementById(wheelType).style.top = start[0]-document.getElementById(wheelType).getBoundingClientRect().height/2+"px";
            document.getElementById(wheelType).style.left = start[1]-document.getElementById(wheelType).getBoundingClientRect().width/2+"px";
            end = [mouse.clientY, mouse.clientX];
            if(Math.sqrt((end[0]-start[0])**2 + (end[1]-start[1])**2) >= innerWheelRadius) {
                if(document.getElementById("newbonklobby_teams_middletext").textContent === "TEAMS OFF") {
                    let angle = end[1] < start[1];
                    if(angle) {
                        document.getElementById("selectionWheel").children[0].children[0].children[0].style.opacity = 1;
                        document.getElementById("selectionWheel").children[0].children[1].children[0].style.opacity = 0.5;
                    }
                    else {
                        document.getElementById("selectionWheel").children[0].children[0].children[0].style.opacity = 0.5;
                        document.getElementById("selectionWheel").children[0].children[1].children[0].style.opacity = 1;
                    }
                    selectedPlayer.onmouseenter(angle);
                    oldAngle = angle;
                }
                else {
                    let angle = Math.atan((end[0]-start[0])/(end[1]-start[1]))/Math.PI*180+360/5/2;
                    if(end[1] < start[1]) {
                        angle += 180;
                    }
                    else if(end[0] < start[0]) {
                        angle += 360;
                    }
                    angle = Math.floor((angle%360)/(360/5));
                    if(oldAngle !== angle) {
                        for(let child of [...document.getElementById("selectionWheelTeams").children[0].children[0].children]) {
                            child.style.opacity = 0.5;
                        }
                    }
                    document.getElementById("selectionWheelTeams").children[0].children[0].children[angle].style.opacity = 1;
                    selectedPlayer.onmouseenter(angle);
                    oldAngle = angle;
                }
            }
            else {
                if(oldAngle !== null) {
                    for(let child of [...document.getElementById("selectionWheelTeams").children[0].children[0].children]) {
                        child.style.opacity = 0.5;
                    }
                    for(let child of [...document.getElementById("selectionWheel").children[0].children]) {
                        child.children[0].style.opacity = 0.5;
                    }
                }
                selectedPlayer.onmouseenter(null);
                oldAngle = null;
            }
        }
    });
    const changeTeam = mouse => {
        document.getElementById("selectionWheel").style.display = "none";
        document.getElementById("selectionWheelTeams").style.display = "none";
        if(!selectedPlayer) return;
        document.body.style.removeProperty("pointer-events");
        end = [mouse.clientY, mouse.clientX];
        if(Math.sqrt((end[0]-start[0])**2 + (end[1]-start[1])**2) >= innerWheelRadius) {
            if(document.getElementById("newbonklobby_teams_middletext").textContent === "TEAMS OFF") {
            for(let child of [...document.getElementById("selectionWheel").children[0].children]) {
                child.children[0].style.opacity = 0.5;
            }
            window.bonkHost.menuUsage.changeOtherTeam(window.bonkHost.players.findIndex(i => {return i && i.userName === selectedPlayer.children[1].textContent}), end[1]<start[1] ? 1 : 0);
            }
            else {
                let angle = Math.atan((end[0]-start[0])/(end[1]-start[1]))/Math.PI*180+360/5/2;
                if(end[1] < start[1]) {
                    angle += 180;
                }
                else if(end[0] < start[0]) {
                    angle += 360;
                }
                angle = Math.floor((angle%360)/(360/5));
                window.bonkHost.menuUsage.changeOtherTeam(window.bonkHost.players.findIndex(i => {return i && i.userName === selectedPlayer.children[1].textContent}), [0, 5, 4, 3, 2][angle]);
            }
        }
        else {
            selectedPlayer.click();
        }
        selectedPlayer = null;
    }
    document.addEventListener("mouseup", changeTeam);
    document.addEventListener("mouseenter", mouse => {selectedPlayer = (mouse.buttons !== 0 ? selectedPlayer : null); if(!selectedPlayer)changeTeam(mouse)});
})();

document.getElementById('ingamechatinputtext').onkeydown = document.getElementById('newbonklobby_chat_input').onkeydown;//Remove round limit
document.getElementById('newbonklobby_roundsinput').removeAttribute("maxlength");
newStr = newStr.replace(/...\[[0-9]\]\[[0-9]\]\[...\[[0-9]\]\[[0-9]?[0-9]?[0-9]\]\]=Math\[...\[[0-9]\]\[[0-9]?[0-9]?[0-9]\]\]\(Math\[...\[[0-9]\]\[[0-9]?[0-9]?[0-9]\]\]\(1,...\[[0-9]\]\[[0-9]\]\[...\[[0-9]\]\[[0-9]?[0-9]?[0-9]\]\]\),9\);/, '');

//Mode selection menu
newStr = newStr.replace(modeStuff[0], `${modeStuff[0]};window.bonkModesObject=${modesObject};window.bonkSetMode=m=>{${modeStuff[1]}${modeVar}=m;${modeStuff[3]}};window.createModeDropdown();`);
//Add mode button to map suggestion message
newStr = newStr.replace('v2k[79][d9G[3][624]]([d9G[73]]);', 'v2k[79][d9G[3][624]]([d9G[73]]);' + SUGGESTION_MODE_BUTTON);
//Append mode button
newStr = newStr.replace('d9G[8][d9G[3][455]](d9G[73]);', 'd9G[8][d9G[3][455]](d9G[73]);'+APPEND_SUGGESTION_MODE_BUTTON);

//Balance all
newStr = newStr.replace('I8H[7][I8H[1][645]]()', 'I8H[7][I8H[1][645]]() || I8H[7] === "*" || I8H[5][0] == "/balanceall"');
newStr = newStr.replace('I8H[5][0] == G9b.z43(1869)', 'I8H[5][0] == G9b.z43(1869) || I8H[5][0] == "/balanceall"');
newStr = newStr.replace('I8H[67]=I8H[17];break;', BALANCE_SELECTION);
newStr = newStr.replace('parseInt(I8H[5][2]);', 'parseInt(I8H[5][I8H[5][0] == "/balanceall" ? 1 : 2]);');
newStr = newStr.replace('if(I8H[32] == 0)', BALANCE_ALL_MESSAGE);

newStr = newStr.replace('if(I8H[5][0] == G9b.z43(1869)', CUSTOM_COMMANDS+'else if(I8H[5][0] == G9b.z43(1869)');
newStr = newStr.replace('u6H[29][I8H[1][644]](G9b.A43(1897),G9b.z43(1871),false);', 'u6H[29][I8H[1][644]](G9b.A43(1897),G9b.z43(1871),false);u6H[29].showStatusMessage("/hhelp - commands from host mod","#cc3333",false);');

//Internal var
newStr = newStr.replace('function I8yy(){}', 'function I8yy(){}'+'I8yy.bonkHost={};');

//Let people join mid game
newStr = newStr.replace('if(u6H[64]){u6H[30]', FREEJOIN + 'u6H[30]');

/////////////
//Host menu//
/////////////

//Add players
newStr = newStr.replace('{Q1h();}};', '{Q1h();}};' + 'window.bonkHost.playerManagement.addPlayer(X9G[1], w3G[0][1][X9G[0][0]]);');

//Remove players
newStr = newStr.replace('if(w3G[32][h9G[5]]){', 'if(w3G[32][h9G[5]]){' + 'window.bonkHost.playerManagement.removePlayer(w3G[32][h9G[5]]);');
newStr = newStr.replace('if(w3G[32][c1G[2]]){', 'if(w3G[32][c1G[2]]){' + 'window.bonkHost.playerManagement.removePlayer(w3G[32][c1G[2]]);');

//Player click menu
newStr = newStr.replace('if(X9G[1][m9G[2][1379]]){', PLAYER_CLICK_MENU + 'if(X9G[1][m9G[2][1379]]){')

//Player click menu position and highligh removal
newStr = newStr.replace('if(m9G[4] == false){', 'if(playerEntry){w3G[26].playerElement=playerEntry;m9G[6].style.removeProperty("left");m9G[6].style.right=0;m9G[6].style.top=([...playerEntry.parentNode.children].indexOf(playerEntry)+1)*43+"px";}' + 'if(m9G[4] == false){');

//Highlight
newStr = newStr.replace('X9G[1][m9G[2][457]][m9G[2][456]](G9b.z43(3256));', 'let playerEntry = window.bonkHost.playerManagement.getPlayer(m9G[0][0].target, true); if(playerEntry) {playerEntry.classList.add("newbonklobby_playerentry_menuhighlighted");} else{' + 'X9G[1][m9G[2][457]][m9G[2][456]](G9b.z43(3256));' + '}');

//Some bonk function handlers
newStr = newStr.replace('R2k[0][1]});};}', 'R2k[0][1]});};' + 'window.bonkHost.bonkHandlers = this;' + '}');

//Some menu functions
newStr = newStr.replace('w3G[60]);}};', 'w3G[60]);}};'+ 'window.bonkHost.menuFunctions = this;');

//Player counter
newStr = newStr.replace('if(u6H[5]', 'window.bonkHost.playerCount=s6H[3];if(u6H[5]');

//Change team handlers
newStr = newStr.replace('w8G[9]=v8yy;', 'w8G[9]=v8yy;' + "window.bonkHost.playerManagement.movePlayer(w8G[0][0], window.bonkHost.playerCount, w8G[0][1]);");
newStr = newStr.replace('S8G[8]=v8yy;', 'S8G[8]=v8yy;' + "window.bonkHost.playerManagement.movePlayer(this.getLSID(), window.bonkHost.playerCount, S8G[0][0]);");

//Get start game function
newStr = newStr.replace('function P5S', 'window.bonkHost.startGameFunction=P5S;document.getElementById("hostPlayerMenuRestartButton").addEventListener("click", window.bonkHost.startGame);' + 'function P5S')

//Scores
newStr = newStr.replace(';if(k7k[0][5][k7k[4][114]])', ';' + KEEP_SCORES + 'if(k7k[0][5][k7k[4][114]])');
newStr = newStr.replace('o9k[1][o9k[7][122]]=[0,0,0,0];', 'o9k[1][o9k[7][122]]=' + '(window.bonkHost.scores.length > 0 && document.getElementById("hostPlayerMenuKeepScores").checked) ? window.bonkHost.scores' + ':[0,0,0,0];')

//Score counter
newStr = newStr.replace('G9b.A2k(1000,b2k[6]);', 'G9b.A2k(1000,b2k[6]);window.bonkHost.scores=i2k[7][i2k[1]].scores;');

//Update menu while in game
newStr = newStr.replace('!this[h9G[9][481]]', '!this[h9G[9][481]] && false');
newStr = newStr.replace('!this[V9G[1][481]]', '!this[V9G[1][481]] && false');

//Show menu when in game if host
newStr = newStr.replace('if(u6H[29]){u6H[29][w8H[9][722]]();}', 'if(u6H[29]){u6H[29][w8H[9][722]]();' + `if(u6H[11].hostID == u6H[11].getLSID())window.bonkHost.playerManagement.show();` + '}');

//Hide menu when not in game
newStr = newStr.replace('w1G[5]=v8yy;', 'w1G[5]=v8yy;' + 'window.bonkHost.playerManagement.hide();window.bonkHost.scores=[];');
newStr = newStr.replace('c1G[5]=v8yy;', 'c1G[5]=v8yy;' + 'window.bonkHost.playerManagement.hide();window.bonkHost.scores=[];');
newStr = newStr.replace('O7G[4]=v8yy;', 'O7G[4]=v8yy;' + 'window.bonkHost.playerManagement.hide();window.bonkHost.scores=[];');

//Add default click handler (mainly for closing the dropdown menu)
newStr = newStr.replace('=e6h;', '=e6h;' + 'document.getElementById("hostPlayerMenu").onclick=e6h;');

//Handle host change
newStr = newStr.replace('l5h(G9b.z43(3279),G9b.A43(3276),false);}', 'window.bonkHost.playerManagement.show();' + 'l5h(G9b.z43(3279),G9b.A43(3276),false);}' + 'else{window.bonkHost.playerManagement.hide();}');
newStr = newStr.replace('C0z(G9b.A43(2039));', 'C0z(G9b.A43(2039));' + 'window.bonkHost.playerManagement.show();');

//Teamlock
newStr = newStr.replace('if(w3G[0][2][V9G[1][662]])', 'document.getElementById("hostPlayerMenuTeamlock").checked=w3G[0][2].tl;' + 'if(w3G[0][2][V9G[1][662]])');

//Handle an error when clicking host menu. MIGHT BREAK IN RARE CASES WITH OTHER MODS because it's missing {}, but it should be fine
newStr = newStr.replace('t9G[5]=v8yy;', 't9G[5]=v8yy;' + 'if(w3G[26].element!=null)');

//Update menu when joined
newStr = newStr.replaceAll('=u6H[30];', '=u6H[30];if(!u6H[64]){let oldVisibility=window.bonkHost.menuFunctions.visible;window.bonkHost.menuFunctions.visible=true;window.bonkHost.menuFunctions.updatePlayers();window.bonkHost.menuFunctions.visible = oldVisibility;}');

//Save latest state
newStr = newStr.replace('var T7k=[arguments];', 'I8yy.bonkHost.state=arguments[0];var T7k=[arguments];');

newStr = newStr.replace('W6H[2][', SET_STATE);

//Get useful menu functions
newStr = newStr.replace('w3G[3]=w3G[0][0];', 'w3G[3]=w3G[0][0];window.bonkHost.menuUsage=w3G[3];');

//Get player lists from updatePlayers() and update player elements for radial menu
newStr = newStr.replace('(1,h9G[2])(h9G[3]);}', '(1,h9G[2])(h9G[3]);}' + 'window.bonkHost.players=w3G[0][1];window.bonkHost.updatePlayers();');

newStr = newStr.replace('m9G[1]=w3G[0][1][X9G[0][0]][m9G[2][115]];', 'm9G[1]=w3G[0][1][X9G[0][0]][m9G[2][115]];' + 'if(!window.bonkHost.menuFunctions.visible && I8yy.bonkHost.state.discs[X9G[0][0]] == undefined && I8yy.bonkHost.state.discDeaths.findIndex(i => {return i.i === X9G[0][0]})){m9G[1]=0;}');

//Fix skin bug
newStr = newStr.replace('u9k[2][u9k[5][457]][u9k[5][456]](i9k[42]);}', 'u9k[2][u9k[5][457]][u9k[5][456]](i9k[42]);}' + "window.bonkHost.redrawSkin(i9k[23]);");	console.log("Bonk Host injector run");
	return newStr;
}

if(!window.bonkCommands) window.bonkCommands = [];

if(!window.bonkCodeInjectors) window.bonkCodeInjectors = [];
window.bonkCodeInjectors.push(bonkCode => {
	try {
		return injector(bonkCode);
	} catch (error) {
		alert(
`Whoops! Bonk Host was unable to load.
This may be due to an update to Bonk.io. If so, please report this error!
This could also be because you have an extension that is incompatible with \
Bonk Host, such as the Bonk Leagues Client. You would have to disable it to use \
Bonk Host.`);
		throw error;
	}
});

console.log("Bonk Host injector loaded");