您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
BonkAPI + BonkHUD
// ==UserScript== // @name BonkLIB // @version 1.1.3 // @author FeiFei + Clarifi + BoZhi // @namespace https://github.com/FeiFei-GH/BonkLIB // @description BonkAPI + BonkHUD // @license MIT // @match https://bonk.io/gameframe-release.html // @run-at document-start // @grant none // ==/UserScript== /* Usable with: https://greasyfork.org/en/scripts/433861-code-injector-bonk-io */ // ! Compitable with Bonk Version 49 window.bonkLIB = {}; bonkLIB.version = "1.1.3"; window.bonkAPI = {}; /** * Contains data of a single player * * @typedef {object} Player * @property {string} peerID - Peer ID of player * @property {string} userName - Username of player * @property {number} level - Level of player * @property {boolean} guest - Is guest * @property {number} team - Integer of what team from 0 to 5 * @property {boolean} ready - Is ready * @property {boolean} tabbed - Is tabbed * @property {JSON} avatar - Skin data */ /** * Contains data of a single friend * * @typedef {object} Friend * @property {string} userName - Username of friend * @property {string} roomID - Room ID of the lobby that the friend is in */ // *Global Variables bonkAPI.currentPlayers = []; //List of user IDs of players in the lobby bonkAPI.playerList = []; // History list of players in the room bonkAPI.myID = -1; // Client's ID bonkAPI.myToken = -1; // Client's token bonkAPI.hostID = -1; // Host's ID bonkAPI.isLoggingIn = false; // MGF vars bonkAPI.bonkWSS = 0; bonkAPI.originalSend = window.WebSocket.prototype.send; bonkAPI.originalRequestAnimationFrame = window.requestAnimationFrame; bonkAPI.originalDrawShape = 0; bonkAPI.pixiCtx = 0; bonkAPI.pixiStage = 0; bonkAPI.parentDraw = 0; bonkAPI.originalXMLOpen = window.XMLHttpRequest.prototype.open; bonkAPI.originalXMLSend = window.XMLHttpRequest.prototype.send; window.bonkHUD = {}; bonkHUD.windowHold = []; bonkHUD.settingsHold = []; //! not used but will be // *Style Store bonkHUD.styleHold = {}; //! styles added do not include color, to be added/changed by user //! some innercss using these classes still has not been deleted(will do it) bonkHUD.bonkHUDCSS = document.createElement("style"); bonkHUD.bonkHUDCSS.innerHTML = ` .bonkhud-settings-row { border-bottom: 1px solid; padding: 10px; } .bonkhud-settings-label { font-size: 0.9rem; font-weight: bold; } .bonkhud-window-container { position: fixed; min-width: 5rem; font-family: "futurept_b1"; border-radius: 8px; z-index: 9990; } .bonkhud-header-button { position: absolute; top: 3px; width: 25px; height: 25px; border-radius: 3px; } .bonkhud-scrollbar-kit::-webkit-scrollbar { display: none; } .bonkhud-scrollbar-other { scrollbar-width: none; } .bonkhud-resizer { width: 10px; height: 10px; background: transparent; position: absolute; } .bonkhud-resizer.north-west { top: -5px; left: -5px; cursor: nwse-resize; } .bonkhud-resizer.north-east { top: -5px; right: -5px; cursor: nesw-resize; } .bonkhud-resizer.south-east { bottom: -5px; right: -5px; cursor: nwse-resize; } .bonkhud-resizer.south-west { bottom: -5px; left: -5px; cursor: nesw-resize; } `; document.getElementsByTagName("head")[0].appendChild(bonkHUD.bonkHUDCSS); /** * Sends message in game's public chat. * @function chat * @param {string} message - The message. */ bonkAPI.chat = function (message) { bonkAPI.sendPacket('42[10,{"message":' + JSON.stringify(message) + "}]"); }; /** * Defaults to banning the player with the given ID. * @function banPlayerByID * @param {number} id - ID of the player to be kicked/banned * @param {boolean} kick - Whether player should be kicked or banned, defaults to false (banned) */ bonkAPI.banPlayerByID = function (id, kick = false) { bonkAPI.sendPacket('42[9,{"banshortid":' + id + ',"kickonly":' + kick + "}]"); }; /** * Gets all online friends. * @function getOnlineFriendList * @param {function} callback - Callback function * @returns {Array.<Friend>} Array of {@linkcode Friend} objects */ bonkAPI.getOnlineFriendList = function (callback) { let req = new window.XMLHttpRequest(); req.onreadystatechange = () => { if (req.readyState == 4) { let friends = []; let data = JSON.parse(req.response)["friends"]; for (let i = 0; i < data.length; i++) { let rid = data[i]["roomid"]; if (rid != null) { friends.push({ userName: data[i]["name"], roomID: rid }); } } callback(friends); } }; try { req.open("POST", "https://bonk2.io/scripts/friends.php"); req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8"); //! maybe make a function to automatically build this stuff, but not necessary and probably worse req.send("token=" + bonkAPI.myToken + "&task=getfriends"); } catch (e) { console.log(e); callback([]); } }; /** * Adds a listener to {@linkcode EventHandler} to call the method. * @function addEventListener * @param {string} event - The event that is listened for * @param {function(object)} method - Method that is called when event is fired * @param {*} [scope] - Defaults to window * @param {*} [context] - Defaults to nothing */ bonkAPI.addEventListener = function (event, method, scope, context) { bonkAPI.events.addEventListener(event, method, scope, context); }; /** * Returns the entire list of {@linkcode Player} objects that have joined * since you have. * @function getPlayerList * @returns {Array.<Player>} Array of {@linkcode Player} objects */ bonkAPI.getPlayerList = function () { // *Returns a copy of bonkAPI.playerList return bonkAPI.playerList; }; /** * Returns list of {@linkcode Player} objects in the lobby at time this * function was called. * @function getPlayerLobbyList * @returns {Array.<Player>} Array of {@linkcode Player} objects */ bonkAPI.getPlayerLobbyList = function () { //! i want to make more playerlobby functions but dk what to name //! or whether to join it with the other functions but add an arguement //! to specify which to use let list = []; bonkAPI.currentPlayers.forEach((index) => { list.push(bonkAPI.playerList[index]); }); return list; } /** * Returns list of user IDs in the lobby at time this * function was called. * @function getPlayersInLobbyID * @returns {Array.<Player>} Array of {@linkcode Player} objects */ bonkAPI.getPlayersInLobbyID = function () { return bonkAPI.currentPlayers; } /** * Returns the amount of players that have been in the lobby. * @function getPlayerListLength * @returns {number} Length of the player list */ bonkAPI.getPlayerListLength = function () { return bonkAPI.playerList.length; }; /** * Returns the {@linkcode Player} object of the ID or name given. * @function getPlayer * @param {*} ref - Either ID of the player or name of the player * @returns {Player} Player object */ bonkAPI.getPlayer = function (ref) { if (typeof ref === "number") { if (ref < 0 || ref >= bonkAPI.playerList.length) { return null; } return bonkAPI.playerList[ref]; } else if (typeof ref === "string") { for (let i = 0; i < bonkAPI.playerList.length; i++) { if (bonkAPI.playerList[i] != null && ref == bonkAPI.playerList[i].userName) { return bonkAPI.playerList[i]; } } return null; } else { return null; } }; /** * Returns the {@linkcode Player} object of the ID given. * @function getPlayerByID * @param {number} id - ID of the player that is being looked for * @returns {Player} Player object */ bonkAPI.getPlayerByID = function (id) { if (id < 0 || id >= bonkAPI.playerList.length) { return null; } return bonkAPI.playerList[id]; }; /** * Returns the {@linkcode Player} object of the name given. * @function getPlayerByName * @param {string} name - Name of the player that is being looked for * @returns {Player} Player object */ bonkAPI.getPlayerByName = function (name) { for (let i = 0; i < bonkAPI.playerList.length; i++) { if (bonkAPI.playerList[i] != null && name == bonkAPI.playerList[i].userName) { return bonkAPI.playerList[i]; } } return null; }; /** * Returns the name of the player of the ID given. * @function getPlayerNameByID * @param id - ID of the player to get the name of * @returns {string} Name of player */ bonkAPI.getPlayerNameByID = function (id) { if (id < 0 || id >= bonkAPI.playerList.length) { return ""; } return bonkAPI.playerList[id].userName; }; /** * Returns the user ID of the player with the given name. * @function getPlayerIDByName * @param {string} name - Name of player to get ID of * @returns {number} ID of player */ bonkAPI.getPlayerIDByName = function (name) { for (let i = 0; i < bonkAPI.playerList.length; i++) { if (bonkAPI.playerList[i] != null && name == bonkAPI.playerList[i].userName) { return i; } } return -1; }; /** * Returns a list of {@linkcode Player} objects that are in the specified * team. * @function getPlayersByTeam * @param {number} team - Team of the player, from 0 to 5 * @returns {Array.<Player>} List of {@linkcode Player} objects */ bonkAPI.getPlayersByTeam = function (team) { var teamList = []; for (let i = 0; i < bonkAPI.playerList.length; i++) { if (team == bonkAPI.playerList[i].team) { teamList.push({ userID: i, userData: bonkAPI.playerList[i] }); } } return teamList; }; /** * Returns your own player ID. * @function getMyID * @returns {number} ID of the user */ bonkAPI.getMyID = function () { return bonkAPI.myID; }; /** * Returns the player ID of the host. * @function getHostID * @returns {number} ID of the host */ bonkAPI.getHostID = function () { return bonkAPI.hostID; }; /** * Returns whether the capzone can be capped * without ending game or desyncing * @function safeToCap * @returns {boolean} Whether it is safe to cap */ bonkAPI.safeToCap = function () { if(bonkAPI.currentPlayers.length == 1) { return true; } let t = bonkAPI.playerList[bonkAPI.currentPlayers[0]].team; for(let i = 1; i < bonkAPI.currentPlayers.length; i++) { if(t != bonkAPI.playerList[bonkAPI.currentPlayers[i]].team && 0 != bonkAPI.playerList[bonkAPI.currentPlayers[i]].team) { return false; } } return true; } /** * Returns whether the game is running after * you have first joined a lobby. * @function isInGame * @returns {boolean} Whether in game or not */ bonkAPI.isInGame = function () { let renderer = document.getElementById("gamerenderer"); return renderer.style.visibility == "inherit"; } window.WebSocket.prototype.send = function (args) { if (this.url.includes("socket.io/?EIO=3&transport=websocket&sid=")) { if (!this.injectedAPI) { // initialize overriding receive listener (only run once) bonkAPI.bonkWSS = this; this.injectedAPI = true; var originalReceive = this.onmessage; // This function intercepts incoming packets this.onmessage = function (args) { // &Receiving incoming packets if(args.data.substring(0, 3) == "42[") { newArgs = JSON.parse(args.data.substring(2)); // !All function names follow verb_noun[verb] format switch (parseInt(newArgs[0])) { case 1: //*Update other players' pings newArgs = bonkAPI.receive_PingUpdate(newArgs); break; case 2: // *UNKNOWN, received after sending create room packet newArgs = bonkAPI.receive_Unknow2(newArgs); break; case 3: // *Room Join newArgs = bonkAPI.receive_RoomJoin(newArgs); break; case 4: // *Player Join newArgs = bonkAPI.receive_PlayerJoin(newArgs); break; case 5: // *Player Leave newArgs = bonkAPI.receive_PlayerLeave(newArgs); break; case 6: // *Host Leave newArgs = bonkAPI.receive_HostLeave(newArgs); break; case 7: // *Receive Inputs newArgs = bonkAPI.receive_Inputs(newArgs); break; case 8: // *Ready Change newArgs = bonkAPI.receive_ReadyChange(newArgs); break; case 13: // *Game End newArgs = bonkAPI.receive_GameEnd(newArgs); break; case 15: // *Game Start newArgs = bonkAPI.receive_GameStart(newArgs); break; case 16: // *Error newArgs = bonkAPI.receive_Error(newArgs); break; case 18: // *Team Change newArgs = bonkAPI.receive_TeamChange(newArgs); break; case 19: // *Teamlock Toggle newArgs = bonkAPI.receive_TeamLockToggle(newArgs); break; case 20: // *Chat Message newArgs = bonkAPI.receive_ChatMessage(newArgs); break; case 21: // *Initial Data newArgs = bonkAPI.receive_InitialData(newArgs); break; case 24: // *Kicked newArgs = bonkAPI.receive_PlayerKick(newArgs); break; case 26: // *Change Mode newArgs = bonkAPI.receive_ModeChange(newArgs); break; case 27: // *Change Rounds newArgs = bonkAPI.receive_RoundsChange(newArgs); break; case 29: // *Map Switch newArgs = bonkAPI.receive_MapSwitch(newArgs); break; case 32: // *inactive? newArgs = bonkAPI.receive_Inactive(newArgs); break; case 33: // *Map Suggest newArgs = bonkAPI.receive_MapSuggest(newArgs); break; case 34: // *Map Suggest Client newArgs = bonkAPI.receive_MapSuggestClient(newArgs); break; case 36: // *Player Balance Change newArgs = bonkAPI.receive_PlayerBalance(newArgs); break; case 40: // *Save Replay newArgs = bonkAPI.receive_ReplaySave(newArgs); break; case 41: // *New Host newArgs = bonkAPI.receive_NewHost(newArgs); break; case 42: // *Friend Req newArgs = bonkAPI.receive_FriendRequest(newArgs); break; case 43: // *Game Starting Countdown newArgs = bonkAPI.receive_CountdownStart(newArgs); break; case 44: // *Abort Countdown newArgs = bonkAPI.receive_CountdownAbort(newArgs); break; case 45: // *Player Leveled Up newArgs = bonkAPI.receive_PlayerLevelUp(newArgs); break; case 46: // *Local Gained XP newArgs = bonkAPI.receive_LocalXPGain(newArgs); break; case 48: newArgs = bonkAPI.receive_gameState(newArgs); break; case 49: // *Created Room Share Link newArgs = bonkAPI.receive_RoomShareLink(newArgs); break; case 52: // *Tabbed newArgs = bonkAPI.receive_Tabbed(newArgs); break; case 58: // *Room Name Update newArgs = bonkAPI.receive_RoomName(newArgs); break; case 59: // *Room Password Update newArgs = bonkAPI.receive_RoomPassword(newArgs); break; } args.data = 42 + JSON.stringify(newArgs); } return originalReceive.call(this, args); }; var originalClose = this.onclose; this.onclose = function () { bonkAPI.bonkWSS = 0; return originalClose.call(this); }; } else { // !All function names follow verb_noun[verb] format if(args.substring(0, 3) == "42[") { args = JSON.parse(args.substring(2)); // &Sending outgoing packets switch (parseInt(args[0])) { case 4: // *Send Inputs args = bonkAPI.send_Inputs(args); break; case 5: // *Trigger Start args = bonkAPI.send_GameStart(args); break; case 6: // *Change Own Team args = bonkAPI.send_TeamChange(args); break; case 7: // *Team Lock args = bonkAPI.send_TeamLock(args); break; case 9: // *Kick/Ban Player args = bonkAPI.send_PlayerKickBan(args); break; case 10: // *Chat Message args = bonkAPI.send_ChatMessage(args); break; case 11: // *Inform In Lobby args = bonkAPI.send_LobbyInform(args); break; case 12: // *Create Room args = bonkAPI.send_RoomCreate(args); break; case 13: // *Room Join Information args = bonkAPI.send_RoomJoin(args); break; case 14: // *Return To Lobby args = bonkAPI.send_LobbyReturn(args); break; case 16: // *Set Ready args = bonkAPI.send_Ready(args); break; case 17: // *All Ready Reset args = bonkAPI.send_AllReadyReset(args); break; case 19: // *Send Map Reorder args = bonkAPI.send_MapReorder(args); break; case 20: // *Send Mode args = bonkAPI.send_ModeChange(args); break; case 21: // *Send WL (Rounds) args = bonkAPI.send_RoundsChange(args); break; case 22: // *Send Map Delete args = bonkAPI.send_MapDelete(args); break; case 23: // *Send Map Switch args = bonkAPI.send_MapSwitch(args); break; case 26: // *Change Other Team args = bonkAPI.send_OtherTeamChange(args); break; case 27: // *Send Map Suggest args = bonkAPI.send_MapSuggest(args); break; case 29: // *Send Balance args = bonkAPI.send_Balance(args); break; case 32: // *Send Team Settings Change args = bonkAPI.send_TeamSetting(args); break; case 33: // *Send Arm Record args = bonkAPI.send_ArmRecord(args); break; case 34: // *Send Host Change args = bonkAPI.send_HostChange(args); break; case 35: // *Send Friended args = bonkAPI.send_Friended(args); break; case 36: // *Send Start Countdown args = bonkAPI.send_CountdownStart(args); break; case 37: // *Send Abort Countdown args = bonkAPI.send_CountdownAbort(args); break; case 38: // *Send Req XP args = bonkAPI.send_XPRequest(args); break; case 39: // *Send Map Vote args = bonkAPI.send_MapVote(args); break; case 40: // *Inform In Game args = bonkAPI.send_InGameInform(args); break; case 41: // *Get Pre Vote args = bonkAPI.send_PreVoteGet(args); break; case 44: // *Tabbed args = bonkAPI.send_Tabbed(args); break; case 50: // *Send No Host Swap args = bonkAPI.send_NoHostSwap(args); break; } args = 42 + JSON.stringify(args); } } } return bonkAPI.originalSend.call(this, args); }; /** * @class EventHandler * @classdesc Stores functions and events and can fire events with data. * This class is already instantiated onto bonkAPI so if you dont need your * own event handler, ignore this class. * @hideconstructor */ bonkAPI.EventHandler; (bonkAPI.EventHandler = function () { this.hasEvent = []; }).prototype = { /** * Begins to listen for the given event to call the method later. * @method * @memberof EventHandler * @param {string} event - Event that is listened for * @param {function(object)} method - Function that is called * @param {*} [scope] - Where the function should be called from, defaults to window * @param {*} [context] - defaults to nothing */ addEventListener: function (event, method, scope, context) { var listeners, handlers; if (!(listeners = this.listeners)) { listeners = this.listeners = {}; } if (!(handlers = listeners[event])) { handlers = listeners[event] = []; this.hasEvent[event] = true; } scope = scope ? scope : window; handlers.push({ method: method, scope: scope, context: context ? context : scope, }); }, /** * Fires the event given to call the methods linked to that event. * @method * @memberof EventHandler * @param {string} event - Event that is being fired * @param {object} data - Data sent along with the event * @param {*} [context] */ fireEvent: function (event, data, context) { var listeners, handlers, handler, l, scope; if (!(listeners = this.listeners)) { return; } if (!(handlers = listeners[event])) { return; } l = handlers.length; for (let i = 0; i < l; i++) { handler = handlers[i]; if (typeof context !== "undefined" && context !== handler.context) { continue; } handler.method.call(handler.scope, data); } }, }; //initialize bonkAPI.events = new bonkAPI.EventHandler(); /** * Triggered when recieving ping updates. * @function receive_PingUpdate * @fires pingUpdate * @param {JSON} args - Packet received by websocket. * @returns {JSON} arguements */ bonkAPI.receive_PingUpdate = function (args) { let pingList = args[1]; let ehcoTo = args[2]; /** * When the user receives ping update. * @event pingUpdate * @type {object} * @property {object} pingList - Other players' ping * @property {number} echoTo - The ID of the player to echo to */ if (bonkAPI.events.hasEvent["pingUpdate"]) { var sendObj = { pingList: pingList, ehcoTo: ehcoTo, }; bonkAPI.events.fireEvent("pingUpdate", sendObj); } return args; }; bonkAPI.receive_Unknow2 = function (args) { // TODO: Finish implement of function return args; }; /** * Triggered when the user joins a lobby. * @function receive_RoomJoin * @fires joinRoom * @fires playerChange * @param {JSON} args - Packet received by websocket. * @returns {JSON} arguements */ bonkAPI.receive_RoomJoin = function (args) { bonkAPI.playerList = []; bonkAPI.myID = args[1]; bonkAPI.hostID = args[2]; for (let i = 0; i < bonkAPI.currentPlayers.length; i++) { /** * When a player leaves or joins. * @event playerChange * @type {object} * @property {number} userID - ID of the player who joined or left * @property {object} userData - Data of the player who joined or left * @property {boolean} hasLeft - Whether the player joined or left */ if (bonkAPI.events.hasEvent["playerChange"]) { var sendObj = { userID: bonkAPI.currentPlayers[i], userData: bonkAPI.playerList[bonkAPI.currentPlayers[i]], hasLeft: true }; bonkAPI.events.fireEvent("playerChange", sendObj); } } bonkAPI.currentPlayers = []; for (let i = 0; i < args[3].length; i++) { bonkAPI.playerList[i] = args[3][i]; if (args[3][i] != null) { bonkAPI.currentPlayers.push(i); /** * When a player leaves or joins. * @event playerChange * @type {object} * @property {number} userID - ID of the player who joined or left * @property {object} userData - Data of the player who joined or left * @property {boolean} hasLeft - Whether the player joined or left */ if (bonkAPI.events.hasEvent["playerChange"]) { var sendObj = { userID: args[1], userData: bonkAPI.playerList[args[1]], hasLeft: false }; bonkAPI.events.fireEvent("playerChange", sendObj); } } } /** * When the user joins a lobby. * @event joinRoom * @type {object} * @property {number} hostID - ID of the host * @property {Array.<Player>} userData - List of players currently in the room * @property {*} roomID - ID of the lobby joined * @property {string} bypass */ if (bonkAPI.events.hasEvent["joinRoom"]) { var sendObj = { hostID: args[2], userData: bonkAPI.playerList, // !May or may not be immutable roomID: args[6], bypass: args[7], }; bonkAPI.events.fireEvent("joinRoom", sendObj); } /** * When a player leaves or joins. * @event playerChange * @type {object} * @property {number} userID - ID of the player who joined or left * @property {object} userData - Data of the player who joined or left * @property {boolean} hasLeft - Whether the player joined or left */ if (bonkAPI.events.hasEvent["playerChange"]) { var sendObj = { userID: args[1], userData: bonkAPI.playerList[args[1]], hasLeft: false }; bonkAPI.events.fireEvent("playerChange", sendObj); } return args; }; /** * Triggered when a player joins the lobby. * @function receive_PlayerJoin * @fires userJoin * @fires playerChange * @param {JSON} args - Packet received by websocket. * @returns {JSON} arguements */ bonkAPI.receive_PlayerJoin = function (args) { bonkAPI.playerList[args[1]] = { peerId: args[2], userName: args[3], guest: args[4], level: args[5], team: args[6], ready: false, tabbed: false, avatar: args[7], }; bonkAPI.currentPlayers.push(args[1]); //? can: //? - send the bonkAPI.playerList as data //? - send the new player object as data //? - send nothing and let the user access bonkAPI.playerList /** * When another player joins the lobby. * @event userJoin * @type {object} * @property {number} userID - ID of the player joined * @property {Player} userData - {@linkcode Player} object data of the player that joined */ if (bonkAPI.events.hasEvent["userJoin"]) { var sendObj = { userID: args[1], userData: bonkAPI.playerList[args[1]] }; bonkAPI.events.fireEvent("userJoin", sendObj); } /** * When a player leaves or joins. * @event playerChange * @type {object} * @property {number} userID - ID of the player who joined or left * @property {object} userData - Data of the player who joined or left * @property {boolean} hasLeft - Whether the player joined or left */ if (bonkAPI.events.hasEvent["playerChange"]) { var sendObj = { userID: args[1], userData: bonkAPI.playerList[args[1]], hasLeft: false }; bonkAPI.events.fireEvent("playerChange", sendObj); } return args; }; /** * Triggered when a player leaves the lobby. * @function receive_PlayerLeave * @fires userLeave * @fires playerChange * @param {JSON} args - Packet received by websocket. * @returns {JSON} arguements */ bonkAPI.receive_PlayerLeave = function (args) { // Remove player from current players bonkAPI.currentPlayers.forEach((n, i) => { if (n == args[1]) { bonkAPI.currentPlayers.splice(i, 1); } }); /** * When another player leaves the lobby. * @event userLeave * @type {object} * @property {number} userID - ID of the player left * @property {Player} userData - {@linkcode Player} object data of the player that left */ if (bonkAPI.events.hasEvent["userLeave"]) { var sendObj = { userID: args[1], userData: bonkAPI.playerList[args[1]] }; bonkAPI.events.fireEvent("userLeave", sendObj); } /** * When a player leaves or joins. * @event playerChange * @type {object} * @property {number} userID - ID of the player who joined or left * @property {object} userData - Data of the player who joined or left * @property {boolean} hasLeft - Whether the player joined or left */ if (bonkAPI.events.hasEvent["playerChange"]) { var sendObj = { userID: args[1], userData: bonkAPI.playerList[args[1]], hasLeft: true }; bonkAPI.events.fireEvent("playerChange", sendObj); } return args; }; /** * Triggered when the host has left. * @function receive_HostLeave * @fires hostChange * @fires userLeave * @fires playerChange * @param {JSON} args - Packet received by websocket. * @returns {JSON} arguements */ bonkAPI.receive_HostLeave = function (args) { let lastHostID = bonkAPI.hostID; bonkAPI.hostID = args[2]; // Remove player from current players bonkAPI.currentPlayers.forEach((n, i) => { if (n == lastHostID) { bonkAPI.currentPlayers.splice(i, 1); } }); /** * When the host changes. * @event hostChange * @type {object} * @property {number} userID - ID of the new host */ //Using hostChange to use for multiple cases if (bonkAPI.events.hasEvent["hostChange"]) { var sendObj = { userID: args[1] }; bonkAPI.events.fireEvent("hostChange", sendObj); } /** * When another player leaves the lobby. * @event userLeave * @type {object} * @property {number} userID - ID of the player left * @property {Player} userData - {@linkcode Player} object data of the player that left */ if (bonkAPI.events.hasEvent["userLeave"]) { var sendObj = { userID: lastHostID, userData: bonkAPI.playerList[lastHostID] }; bonkAPI.events.fireEvent("userLeave", sendObj); } /** * When a player leaves or joins. * @event playerChange * @type {object} * @property {number} userID - ID of the player who joined or left * @property {object} userData - Data of the player who joined or left * @property {boolean} hasLeft - Whether the player joined or left */ if (bonkAPI.events.hasEvent["playerChange"]) { var sendObj = { userID: lastHostID, userData: bonkAPI.playerList[lastHostID], hasLeft: true }; bonkAPI.events.fireEvent("playerChange", sendObj); } return args; }; /** * Triggered when a player sends an input. * @function receive_Inputs * @fires gameInputs * @param {JSON} args - Packet received by websocket. * @returns {JSON} arguements */ bonkAPI.receive_Inputs = function (args) { /* * Maybe we could have different event names like * "receiveRawInput" and "receiveInput" which send * different data, the second could have booleans * representing the inputs, the other is binary */ /** * When inputs are received from other players. * @event gameInputs * @type {object} * @property {number} userID - ID of the player who inputted * @property {number} rawInput - Input of the player in the form of 6 bits * @property {number} frame - Frame when input happened * @property {number} sequence - The total amount of inputs by that player */ if (bonkAPI.events.hasEvent["gameInputs"]) { var sendObj = { userID: args[1], rawInput: args[2]["i"], frame: args[2]["f"], sequence: args[2]["c"], }; bonkAPI.events.fireEvent("gameInputs", sendObj); } //example /*if(bonkAPI.bonkAPI.events.hasEvent["receiveRawInput"]) { obj here bonkAPI.bonkAPI.events.fireEvent("receiveRawInput", sendObj); } */ return args; }; bonkAPI.receive_ReadyChange = function (args) { // TODO: Finish implement of function return args; }; bonkAPI.receive_GameEnd = function (args) { // TODO: Finish implement of function return args; }; //! Detects when match starts!!! /** * Triggered when the game starts. * @function receive_GameStart * @fires gameStart * @param {JSON} args - Packet received by websocket. * @returns {JSON} arguements */ bonkAPI.receive_GameStart = function (args) { /** * When game has started * @event gameStart * @type {object} * @property {string} mapData - Encoded map data, must decode it to use * @property {object} startData - Extra game specific data */ if (bonkAPI.events.hasEvent["gameStart"] && bonkAPI.myID != bonkAPI.hostID) { //! change name of mapdata since it is not map data, probably gamestate //! do the same in triggerstart var sendObj = { mapData: bonkAPI.ISdecode(args[2]), startData: args[3], }; bonkAPI.events.fireEvent("gameStart", sendObj); } return args; }; bonkAPI.receive_Error = function (args) { // TODO: Finish implement of function return args; }; /** * Triggered when a player changes team. * @function receive_TeamChange * @fires teamChange * @param {JSON} args - Packet received by websocket. * @returns {JSON} arguements */ bonkAPI.receive_TeamChange = function (args) { bonkAPI.playerList[parseInt(args[1])].team = args[2]; /** * When a player has changed teams. * @event teamChange * @type {object} * @property {number} userID - Player who changed teams * @property {number} team - The new team, represented from 0 to 5 */ if (bonkAPI.events.hasEvent["teamChange"]) { var sendObj = { userID: args[1], team: args[2] }; bonkAPI.events.fireEvent("teamChange", sendObj); } return args; }; bonkAPI.receive_TeamLockToggle = function (args) { // TODO: Finish implement of function return args; }; /** * Triggered when received a message. * @function receive_ChatMessage * @fires chatIn * @param {JSON} args - Packet received by websocket. * @returns {JSON} arguements */ bonkAPI.receive_ChatMessage = function (args) { let chatUserID = args[1]; let chatMessage = args[2]; /** * When the user has received a message. * @event chatIn * @type {object} * @property {number} userID - Player who chatted * @property {string} message - The message received */ if (bonkAPI.events.hasEvent["chatIn"]) { var sendObj = { userID: chatUserID, message: chatMessage }; bonkAPI.events.fireEvent("chatIn", sendObj); } return args; }; /** * Data given by host after join. * @function receive_InitialData * @fires modeChange * @param {JSON} args - Packet received by websocket. * @returns {JSON} arguements */ bonkAPI.receive_InitialData = function (args) { /** * When the mode has changed. * @event modeChange * @type {object} * @property {string} mode - Short string representing the new mode */ if (bonkAPI.events.hasEvent["modeChange"]) { var sendObj = { mode: args[1]["mo"] }; bonkAPI.events.fireEvent("modeChange", sendObj); } return args; }; bonkAPI.receive_PlayerKick = function (args) { // TODO: Finish implement of function return args; }; /** * Triggered when the mode changes. * @function receive_ModeChange * @fires modeChange * @param {JSON} args - Packet received by websocket. * @returns {JSON} arguements */ bonkAPI.receive_ModeChange = function (args) { // *Maybe change raw arguement to full mode name or numbers /** * When the mode has changed. * @event modeChange * @type {object} * @property {string} mode - Short string representing the new mode */ if (bonkAPI.events.hasEvent["modeChange"]) { var sendObj = { mode: args[1] }; bonkAPI.events.fireEvent("modeChange", sendObj); } return args; }; bonkAPI.receive_RoundsChange = function (args) { // TODO: Finish implement of function return args; }; /** * Triggered when map has changed. * @function receive_MapSwitch * @fires mapSwitch * @param {JSON} args - Packet received by websocket. * @returns {JSON} arguements */ bonkAPI.receive_MapSwitch = function (args) { // *Using mapSwitch to stick with other bonkAPI.events using "change" /** * When the map has changed. * @event mapSwitch * @type {object} * @property {string} mapData - String with the data of the map */ if (bonkAPI.events.hasEvent["mapSwitch"]) { var sendObj = { mapData: args[1] }; bonkAPI.events.fireEvent("mapSwitch", sendObj); } return args; }; bonkAPI.receive_Inactive = function (args) { // TODO: Finish implement of function return args; }; bonkAPI.receive_MapSuggest = function (args) { // TODO: Finish implement of function return args; }; bonkAPI.receive_MapSuggestClient = function (args) { // TODO: Finish implement of function return args; }; bonkAPI.receive_PlayerBalance = function (args) { // TODO: Finish implement of function return args; }; bonkAPI.receive_ReplaySave = function (args) { // TODO: Finish implement of function return args; }; /** * Triggered when there is a new host. * @function receive_NewHost * @fires hostChange * @param {JSON} args - Packet received by websocket. * @returns {JSON} arguements */ bonkAPI.receive_NewHost = function (args) { bonkAPI.hostID = args[1]["newHost"]; /** * When the host changes. * @event hostChange * @type {object} * @property {number} userID - ID of the new host */ if (bonkAPI.events.hasEvent["hostChange"]) { var sendObj = { userID: args[1]["newHost"] }; bonkAPI.events.fireEvent("hostChange", sendObj); } return args; }; /** * Triggered when the user receives a friend request. * @function receive_FriendReq * @fires receivedFriend * @param {JSON} args - Packet received by websocket. * @returns {JSON} arguements */ bonkAPI.receive_FriendRequest = function (args) { /** * When the the user has been friended. * @event receivedFriend * @type {object} * @property {number} userID - ID of the player who friended you */ if (bonkAPI.events.hasEvent["receivedFriend"]) { var sendObj = { userID: args[1] }; bonkAPI.events.fireEvent("receivedFriend", sendObj); } return args; }; bonkAPI.receive_CountdownStart = function (args) { // TODO: Finish implement of function return args; }; bonkAPI.receive_CountdownAbort = function (args) { // TODO: Finish implement of function return args; }; bonkAPI.receive_PlayerLevelUp = function (args) { // TODO: Finish implement of function return args; }; bonkAPI.receive_LocalXPGain = function (args) { // TODO: Finish implement of function return args; }; /** * Triggers after joining a room and the * game state is sent. * @function receive_gameState * @fires modeChange * @fires gameStart * @param {JSON} args - Packet received by websocket. * @returns {JSON} arguements */ bonkAPI.receive_gameState = function (args) { //! also needs to fire something to do with gamestate /** * When the mode has changed. * @event modeChange * @type {object} * @property {string} mode - Short string representing the new mode */ if (bonkAPI.events.hasEvent["modeChange"]) { var sendObj = { mode: args[1]["gs"]["mo"] }; bonkAPI.events.fireEvent("modeChange", sendObj); } /** * When game has started * @event gameStart * @type {object} * @property {string} mapData - Encoded map data, must decode it to use * @property {object} startData - Extra game specific data */ if (bonkAPI.events.hasEvent["gameStart"]) { //! change name of mapdata since it is not map data, probably gamestate //! do the same in triggerstart var sendObj = { mapData: bonkAPI.decodeMap(args[1]["gs"]["map"]), startData: args[3], }; bonkAPI.events.fireEvent("gameStart", sendObj); } return args; }; bonkAPI.receive_RoomShareLink = function (args) { // TODO: Finish implement of function return args; }; bonkAPI.receive_Tabbed = function (args) { // TODO: Finish implement of function return args; }; bonkAPI.receive_RoomName = function (args) { // TODO: Finish implement of function return args; }; bonkAPI.receive_RoomPassword = function (args) { // TODO: Finish implement of function return args; }; /** * Called when sending inputs out. * @function send_Inputs * @param {JSON} args - Packet received by websocket. * @returns {JSON} arguements */ bonkAPI.send_Inputs = function (args) { /** * When inputs are received from other players. * @event gameInputs * @type {object} * @property {number} userID - ID of the player who inputted * @property {number} rawInput - Input of the player in the form of 6 bits * @property {number} frame - Frame when input happened * @property {number} sequence - The total amount of inputs by that player */ if (bonkAPI.events.hasEvent["gameInputs"]) { var sendObj = { userID: bonkAPI.myID, rawInput: args[1]["i"], frame: args[1]["f"], sequence: args[1]["c"], }; bonkAPI.events.fireEvent("gameInputs", sendObj); } return args; }; /** * Called when started the game. * @function send_GameStart * @param {JSON} args - Packet received by websocket. * @returns {JSON} arguements */ bonkAPI.send_GameStart = function (args) { /** * When game has started * @event gameStart * @type {object} * @property {string} mapData - Encoded map data, must decode it to use * @property {object} startData - Extra game specific data */ if (bonkAPI.events.hasEvent["gameStart"]) { //! do something to mapData so it will encode it //! then assign it back to the args var sendObj = { mapData: bonkAPI.ISdecode(args[1]["is"]), startData: args[1]["gs"], }; bonkAPI.events.fireEvent("gameStart", sendObj); //!possibly temporary //allows start packet to be edited args[1]["is"] = bonkAPI.ISencode(sendObj.mapData); } return args; }; bonkAPI.send_TeamChange = function (args) { // TODO: Finish implement of function return args; }; bonkAPI.send_TeamLock = function (args) { // TODO: Finish implement of function return args; }; bonkAPI.send_PlayerKickBan = function (args) { // TODO: Finish implement of function return args; }; bonkAPI.send_ChatMessage = function (args) { // TODO: Finish implement of function return args; }; bonkAPI.send_LobbyInform = function (args) { // TODO: Finish implement of function return args; }; /** * Called when created a room. * @function send_RoomCreate * @fires createRoom * @fires playerChange * @param {JSON} args - Packet received by websocket. * @returns {JSON} arguements */ bonkAPI.send_RoomCreate = function (args) { bonkAPI.playerList = []; for (let i = 0; i < bonkAPI.currentPlayers.length; i++) { /** * When a player leaves or joins. * @event playerChange * @type {object} * @property {number} userID - ID of the player who joined or left * @property {object} userData - Data of the player who joined or left * @property {boolean} hasLeft - Whether the player joined or left */ if (bonkAPI.events.hasEvent["playerChange"]) { var sendObj = { userID: bonkAPI.currentPlayers[i], userData: bonkAPI.playerList[bonkAPI.currentPlayers[i]], hasLeft: true }; bonkAPI.events.fireEvent("playerChange", sendObj); } } bonkAPI.currentPlayers = []; bonkAPI.playerList[0] = { peerId: args[1]["peerID"], userName: document.getElementById("pretty_top_name").textContent, level: document.getElementById("pretty_top_level").textContent == "Guest" ? 0 : parseInt(document.getElementById("pretty_top_level").textContent.substring(3)), guest: typeof args[1].token == "undefined", team: 1, ready: false, tabbed: false, avatar: args[1]["avatar"], }; bonkAPI.currentPlayers.push(0); bonkAPI.myID = 0; bonkAPI.hostID = 0; /** * When you create a room. * @event createRoom * @type {object} * @property {number} userID - ID of you * @property {object} userData - Your player data */ if (bonkAPI.events.hasEvent["createRoom"]) { var sendObj = { userID: 0, userData: bonkAPI.playerList[0] }; bonkAPI.events.fireEvent("createRoom", sendObj); } /** * When a player leaves or joins. * @event playerChange * @type {object} * @property {number} userID - ID of the player who joined or left * @property {object} userData - Data of the player who joined or left * @property {boolean} hasLeft - Whether the player joined or left */ if (bonkAPI.events.hasEvent["playerChange"]) { var sendObj = { userID: 0, userData: bonkAPI.playerList[0], hasLeft: false }; bonkAPI.events.fireEvent("playerChange", sendObj); } return args; }; /** * Called as to send inital user data when joining a room. * @function send_RoomJoin * @fires roomJoin * @param {JSON} args - Packet received by websocket. * @returns {JSON} arguements */ bonkAPI.send_RoomJoin = function (args) { //! DONT KNOW WHAT TO DO FOR NAMING //! Possibly get rid of XMLhttp thing since this gives the login token /** * When inputs are received from other players. * @event roomJoin * @type {object} * @property {string} password - Room password * @property {object} avatar - User's avatar * @property {string} token - Login token */ if (bonkAPI.events.hasEvent["roomJoin"]) { var sendObj = { password: args[1]["roomPassword"], avatar: args[1]["avatar"], token: args[1]["token"] ? args[1]["token"] : null, }; bonkAPI.events.fireEvent("roomJoin", sendObj); } return args; }; bonkAPI.send_LobbyReturn = function (args) { // TODO: Finish implement of function return args; }; bonkAPI.send_Ready = function (args) { // TODO: Finish implement of function return args; }; bonkAPI.send_AllReadyReset = function (args) { // TODO: Finish implement of function return args; }; bonkAPI.send_MapReorder = function (args) { // TODO: Finish implement of function return args; }; /** * When you change modes. * @function send_ModeChange * @fires modeChange * @param {JSON} args - Packet received by websocket. * @returns {JSON} arguements */ bonkAPI.send_ModeChange = function (args) { // TODO: Finish implement of function /** * When the mode has changed. * @event modeChange * @type {object} * @property {string} mode - Short string representing the new mode */ if (bonkAPI.events.hasEvent["modeChange"]) { var sendObj = { mode: args[1]["mo"] }; bonkAPI.events.fireEvent("modeChange", sendObj); } return args; }; bonkAPI.send_RoundsChange = function (args) { // TODO: Finish implement of function return args; }; bonkAPI.send_MapDelete = function (args) { // TODO: Finish implement of function return args; }; /** * Called when user changes map. * @function send_MapSwitch * @param {JSON} args - Packet received by websocket. * @returns {JSON} arguements */ bonkAPI.send_MapSwitch = function (args) { // *Using mapSwitch to stick with other bonkAPI.events using "change" /** * When the map has changed. * @event mapSwitch * @type {object} * @property {string} mapData - String with the data of the map */ if (bonkAPI.events.hasEvent["mapSwitch"]) { var sendObj = { mapData: args[1]["m"] }; bonkAPI.events.fireEvent("mapSwitch", sendObj); } return args; }; bonkAPI.send_OtherTeamChange = function (args) { // TODO: Finish implement of function return args; }; bonkAPI.send_MapSuggest = function (args) { // TODO: Finish implement of function return args; }; bonkAPI.send_Balance = function (args) { // TODO: Finish implement of function return args; }; bonkAPI.send_TeamSetting = function (args) { // TODO: Finish implement of function return args; }; bonkAPI.send_ArmRecord = function (args) { // TODO: Finish implement of function return args; }; bonkAPI.send_HostChange = function (args) { // TODO: Finish implement of function return args; }; bonkAPI.send_Friended = function (args) { // TODO: Finish implement of function return args; }; bonkAPI.send_CountdownStart = function (args) { // TODO: Finish implement of function return args; }; bonkAPI.send_CountdownAbort = function (args) { // TODO: Finish implement of function return args; }; bonkAPI.send_XPRequest = function (args) { // TODO: Finish implement of function return args; }; bonkAPI.send_MapVote = function (args) { // TODO: Finish implement of function return args; }; bonkAPI.send_InGameInform = function (args) { // TODO: Finish implement of function return args; }; bonkAPI.send_PreVoteGet = function (args) { // TODO: Finish implement of function return args; }; bonkAPI.send_Tabbed = function (args) { // TODO: Finish implement of function return args; }; bonkAPI.send_NoHostSwap = function (args) { // TODO: Finish implement of function return args; }; window.XMLHttpRequest.prototype.open = function (_, url) { if (url.includes("scripts/login_legacy")) { bonkAPI.isLoggingIn = true; } //? Could check for other post requests but not necessary bonkAPI.originalXMLOpen.call(this, ...arguments); }; window.XMLHttpRequest.prototype.send = function (data) { if (bonkAPI.isLoggingIn) { this.onreadystatechange = function () { if (this.readyState == 4) { bonkAPI.myToken = JSON.parse(this.response)["token"]; } }; bonkAPI.isLoggingIn = false; } bonkAPI.originalXMLSend.call(this, ...arguments); }; // *Injecting code into src bonkAPI.injector = function (src) { let newSrc = src; //! Inject capZoneEvent fire let orgCode = `K$h[9]=K$h[0][0][K$h[2][138]]()[K$h[2][115]];`; let newCode = ` K$h[9]=K$h[0][0][K$h[2][138]]()[K$h[2][115]]; bonkAPI_capZoneEventTry: try { // Initialize let inputState = z0M[0][0]; let currentFrame = inputState.rl; let playerID = K$h[0][0].m_userData.arrayID; let capID = K$h[1]; let sendObj = { capID: capID, playerID: playerID, currentFrame: currentFrame }; if (window.bonkAPI.events.hasEvent["capZoneEvent"]) { window.bonkAPI.events.fireEvent("capZoneEvent", sendObj); } } catch(err) { console.error("ERROR: capZoneEvent"); console.error(err); }`; newSrc = newSrc.replace(orgCode, newCode); //! Inject stepEvent fire orgCode = `return z0M[720];`; newCode = ` bonkAPI_stepEventTry: try { let inputStateClone = JSON.parse(JSON.stringify(z0M[0][0])); let currentFrame = inputStateClone.rl; let gameStateClone = JSON.parse(JSON.stringify(z0M[720])); let sendObj = { inputState: inputStateClone, gameState: gameStateClone, currentFrame: currentFrame }; if (window.bonkAPI.events.hasEvent["stepEvent"]) { window.bonkAPI.events.fireEvent("stepEvent", sendObj); } } catch(err) { console.error("ERROR: stepEvent"); console.error(err); } return z0M[720];`; newSrc = newSrc.replace(orgCode, newCode); //! Inject frameIncEvent fire //TODO: update to bonk 49 orgCode = `Y3z[8]++;`; newCode = ` Y3z[8]++; bonkAPI_frameIncEventTry: try { if (window.bonkAPI.events.hasEvent["frameIncEvent"]) { var sendObj = { frame: Y3z[8], gameStates: o3x[7] }; window.bonkAPI.events.fireEvent("frameIncEvent", sendObj); } } catch(err) { console.error("ERROR: frameIncEvent"); console.error(err); }`; // newSrc = newSrc.replace(orgCode, newCode); return newSrc; }; // Compatibility with Excigma's code injector userscript if (!window.bonkCodeInjectors) window.bonkCodeInjectors = []; window.bonkCodeInjectors.push((bonkCode) => { try { return bonkAPI.injector(bonkCode); } catch (error) { alert(`Injecting failed, BonkAPI may lose some functionality. This may be due to an update by Chaz.`); throw error; } }); // TODO: these could be dangerous, maybe add some sanitization // *Send a packet to server /** * Sends the given packet to bonk servers. * @function bonkAPI.sendPacket * @param {string} packet - Packet to send to bonk */ bonkAPI.sendPacket = function (packet) { if (bonkAPI.bonkWSS != 0) { bonkAPI.bonkWSS.send(packet); } }; // *Make client receive a packet /** * Makes your client receive the given packet. * @function bonkAPI.receivePacket * @param {string} packet - Packet that is received */ bonkAPI.receivePacket = function (packet) { if (bonkAPI.bonkWSS != 0) { bonkAPI.bonkWSS.onmessage({ data: packet }); } }; bonkHUD.createWindow = function (windowName, windowContent, opts = {}) { //* leaving this for backwards compatability fr let id = "bonkHUD_window_" + windowName; let modVersion = "1.0.0"; if(opts.hasOwnProperty("windowId")) { id = opts.windowId } if(opts.hasOwnProperty("modVersion")) { modVersion = opts.modVersion } if(opts.hasOwnProperty("bonkLIBVersion")) { if(opts.bonkLIBVersion != bonkLIB.version) { if(typeof opts.bonkLIBVersion === 'string') { if(opts.bonkLIBVersion.substring(0, opts.bonkLIBVersion.lastIndexOf(".")) != bonkLIB.version.substring(0, bonkLIB.version.lastIndexOf("."))) alert(windowName + " may not be compatible with current version of BonkLIB ("+opts.bonkLIBVersion+" =/= "+bonkLIB.version+")"); console.log(windowName + " may not be compatible with current version of BonkLIB ("+opts.bonkLIBVersion+" =/= "+bonkLIB.version+")"); } else { alert("Version is incompatible, please check with mod maker to fix"); } } } //! ignoring for now /*if(opts.hasOwnProperty("bonkVersion")) { }*/ let idCounter = 0 while(document.getElementById(id) != null) { id = "bonkHUD_window_" + windowName + idCounter idCounter++ } //(name, id, recVersion, bodyHTML, settingElement = 0) { let ind = bonkHUD.settingsHold.length; bonkHUD.settingsHold.push(id) bonkHUD.windowHold[ind] = { id: id }; bonkHUD.windowHold[ind] = bonkHUD.getUISetting(ind) // Create Settings controller let fullSettingsDiv = document.createElement("div"); bonkHUD.createWindowControl(ind, fullSettingsDiv); if(opts.hasOwnProperty("settingsContent")) { bonkHUD.createSettingsControl(opts.settingsContent, fullSettingsDiv); } bonkHUD.createMenuHeader(windowName, fullSettingsDiv, modVersion); //! POSSIBLY MOVE EVERYTHING ABOVE TO createMod TO MAKE CLEANER BUT NOT BACKWARDS COMPATIBLE // Create the main container 'dragItem' let dragItem = document.createElement("div"); dragItem.classList.add("bonkhud-window-container"); dragItem.classList.add("bonkhud-background-color"); dragItem.classList.add("windowShadow"); dragItem.id = id + "-drag"; dragItem.style.overflowX = "hidden"; dragItem.style.overflowY = "hidden"; dragItem.style.bottom = bonkHUD.windowHold[ind].bottom; //top ? top : "0"; dragItem.style.right = bonkHUD.windowHold[ind].right; //left ? left : "0"; dragItem.style.width = bonkHUD.windowHold[ind].width; //width ? width : "172"; dragItem.style.height = bonkHUD.windowHold[ind].height; //height ? height : minHeight; //dragItem.style.minHeight = minHeight; // Minimum height to prevent deformation dragItem.style.display = bonkHUD.windowHold[ind].display; dragItem.style.visibility = "visible"; dragItem.style.opacity = bonkHUD.windowHold[ind].opacity; let dragNW = document.createElement("div"); dragNW.classList.add("bonkhud-resizer"); dragNW.classList.add("north-west"); let dragNE = document.createElement("div"); dragNE.classList.add("bonkhud-resizer"); dragNE.classList.add("north-east"); let dragSE = document.createElement("div"); dragSE.classList.add("bonkhud-resizer"); dragSE.classList.add("south-east"); let dragSW = document.createElement("div"); dragSW.classList.add("bonkhud-resizer"); dragSW.classList.add("south-west"); // Create the header let header = document.createElement("div"); header.classList.add("bonkhud-drag-header"); header.classList.add("newbonklobby_boxtop"); header.classList.add("newbonklobby_boxtop_classic"); header.classList.add("bonkhud-header-color"); header.style.borderRadius = "0px"; header.style.visibility = "visible"; // Create the title span let title = document.createElement("span"); title.classList.add("bonkhud-drag-header"); title.classList.add("bonkhud-title-color"); title.textContent = windowName; title.style.flexGrow = "1"; title.style.textAlign = "center"; // Create the resize button let openCloseButton = document.createElement("div"); openCloseButton.classList.add("bonkhud-header-button"); openCloseButton.classList.add("bonkhud-title-color"); openCloseButton.classList.add("bonkhud-resize"); openCloseButton.innerText = "△"; // Use an appropriate icon or text openCloseButton.style.fontSize = "15px"; openCloseButton.style.lineHeight = "25px"; openCloseButton.style.textIndent = "5px"; openCloseButton.style.cursor = "cell"; let closeButton = document.createElement("div"); closeButton.classList.add("bonkhud-header-button"); closeButton.classList.add("bonkhud-title-color"); closeButton.innerText = "_"; // Use an appropriate icon or text closeButton.style.lineHeight = "9px"; closeButton.style.right = "3px"; closeButton.style.cursor = "pointer"; // Append the title and resize button to the header header.appendChild(title); header.appendChild(openCloseButton); header.appendChild(closeButton); // Append the header to the dragItem dragItem.appendChild(dragNW); dragItem.appendChild(dragNE); dragItem.appendChild(dragSE); dragItem.appendChild(dragSW); dragItem.appendChild(header); // Create the key table windowContent.id = id; windowContent.classList.add("bonkhud-text-color"); windowContent.classList.add("bonkhud-scrollbar-kit"); windowContent.classList.add("bonkhud-scrollbar-other"); windowContent.style.overflowY = "scroll"; windowContent.style.padding = "5px"; windowContent.style.width = "calc(100% - 10px)"; windowContent.style.height = "calc(100% - 42px)"; // Adjusted height for header // Append the content to the dragItem dragItem.appendChild(windowContent); // Append the dragItem to the body of the page document.body.appendChild(dragItem); closeButton.addEventListener('click', (e) => { dragItem.style.display = "none"; let visCheck = document.getElementById(id + "-visibility-check"); visCheck.checked = false; bonkHUD.windowHold[ind].display = dragItem.style.display; bonkHUD.saveUISetting(ind); }); // Add event listeners for dragging dragItem.addEventListener('mousedown', (e) => bonkHUD.dragStart(e, dragItem, ind)); // Add event listeners for resizing openCloseButton.addEventListener('mousedown', (e) => { if(openCloseButton.innerText == "△") { dragItem.style.visibility = "hidden"; header.style.borderRadius = "8px"; openCloseButton.innerText = "▽"; } else { dragItem.style.visibility = "visible"; header.style.borderRadius = "0px"; openCloseButton.innerText = "△"; } }); dragNW.addEventListener('mousedown', (e) => bonkHUD.startResizing(e, dragItem, "nw", ind)); dragNE.addEventListener('mousedown', (e) => bonkHUD.startResizing(e, dragItem, "ne", ind)); dragSE.addEventListener('mousedown', (e) => bonkHUD.startResizing(e, dragItem, "se", ind)); dragSW.addEventListener('mousedown', (e) => bonkHUD.startResizing(e, dragItem, "sw", ind)); bonkHUD.updateStyleSettings(); //! probably slow but it works, its not like someone will have 100's of windows return ind; }; bonkHUD.createMod = function (modName, opts = {}) { if(opts.hasOwnProperty("bonkLIBVersion")) { if(opts.bonkLIBVersion != bonkLIB.version) { if(typeof opts.bonkLIBVersion === 'string') { if(opts.bonkLIBVersion.substring(0, opts.bonkLIBVersion.lastIndexOf(".")) != bonkLIB.version.substring(0, bonkLIB.version.lastIndexOf("."))) alert(windowName + " may not be compatible with current version of BonkLIB ("+opts.bonkLIBVersion+" =/= "+bonkLIB.version+")"); console.log(windowName + " may not be compatible with current version of BonkLIB ("+opts.bonkLIBVersion+" =/= "+bonkLIB.version+")"); } else { alert("Version is incompatible, please check with mod maker to fix"); } } } if(opts.hasOwnProperty("noWindow") && opts.noWindow) { let id = modName; let modVersion = "1.0.0"; if(opts.hasOwnProperty("modVersion")) { modVersion = opts.modVersion; } let ind = bonkHUD.settingsHold.length; bonkHUD.settingsHold.push(id) // Create Settings controller let fullSettingsDiv = document.createElement("div"); if(opts.hasOwnProperty("settingsContent")) { bonkHUD.createSettingsControl(opts.settingsContent, fullSettingsDiv); } bonkHUD.createMenuHeader(modName, fullSettingsDiv, modVersion); return ind; } else { if(opts.hasOwnProperty("windowContent")) { return bonkHUD.createWindow(modName, opts.windowContent, opts); } } }; bonkHUD.dragStart = function (e, dragItem, ind) { bonkHUD.focusWindow(dragItem); // Prevents dragging from starting on the opacity slider if (e.target.classList.contains("bonkhud-drag-header") && !e.target.classList.contains("bonkhud-resize")) { let startX = e.clientX; let startY = e.clientY; let startRight = parseInt(window.getComputedStyle(dragItem).right, 10); let startBottom = parseInt(window.getComputedStyle(dragItem).bottom, 10); const boundDragMove = bonkHUD.dragMove.bind(null, startX, startY, startRight, startBottom, dragItem); document.addEventListener('mousemove', boundDragMove); document.addEventListener('mouseup', () => bonkHUD.dragEnd(boundDragMove, dragItem, ind), { once: true }); } }; bonkHUD.dragMove = function (startX, startY, startRight, startBottom, dragItem, e) { let w = parseFloat(window.getComputedStyle(dragItem).width) / 2; let h = parseFloat(window.getComputedStyle(dragItem).height) / 2; let moveX = bonkHUD.clamp(startRight + startX - e.clientX, -w, window.innerWidth - w); let moveY = bonkHUD.clamp(startBottom + startY - e.clientY, -h, window.innerHeight - h * 2 + 15); dragItem.style.right = bonkHUD.pxTorem(moveX) + "rem"; dragItem.style.bottom = bonkHUD.pxTorem(moveY) + "rem"; }; bonkHUD.dragEnd = function (dragMoveFn, dragItem, ind) { document.removeEventListener('mousemove', dragMoveFn); bonkHUD.windowHold[ind].width = dragItem.style.width; bonkHUD.windowHold[ind].height = dragItem.style.height; bonkHUD.windowHold[ind].bottom = dragItem.style.bottom; bonkHUD.windowHold[ind].right = dragItem.style.right; bonkHUD.saveUISetting(ind); }; // !Right now only useful for mods that have a setting that **only** // !needs to be read from bonkHUD.saveModSetting = function (ind, obj) { let save_id = 'bonkHUD_Mod_Setting_' + bonkHUD.settingsHold[ind]; localStorage.setItem(save_id, JSON.stringify(obj)); }; bonkHUD.getModSetting = function (ind) { let save_id = 'bonkHUD_Mod_Setting_' + bonkHUD.settingsHold[ind]; let setting = JSON.parse(localStorage.getItem(save_id)); if (!setting) { // !let mod maker handle it return null; } return setting; }; /*bonkHUD.loadModSetting = function (id) { let windowElement = document.getElementById(id + "-drag"); if (windowElement) { Object.assign(windowElement.style, bonkHUD.getUISetting(id)); } else { console.log(`bonkHUD.loadModSetting: Window element not found for id: ${id}. Please ensure the window has been created.`); } };*/ bonkHUD.resetModSetting = function (ind) { try { let save_id = 'bonkHUD_Mod_Setting_' + bonkHUD.settingsHold[ind]; localStorage.removeItem(save_id); //Object.assign(windowElement.style, bonkHUD.getUISetting(id)); } catch(er) { console.log(`bonkHUD.resetModSetting: Settings for ${bonkHUD.settingsHold[ind]} were not found.`); } }; bonkHUD.createSettingsControl = function (settingsElement, element) { element.appendChild(settingsElement) //bonkHUD.settingsHold[ind].settings.appendChild(settingsElement); }; // Function to start resizing the UI bonkHUD.startResizing = function (e, dragItem, dir, ind) { e.stopPropagation(); // Prevent triggering dragStart for dragItem let startX = e.clientX; let startY = e.clientY; let windowX = parseInt(window.getComputedStyle(dragItem).right, 10); let windowY = parseInt(window.getComputedStyle(dragItem).bottom, 10); let startWidth = parseInt(window.getComputedStyle(dragItem).width, 10); let startHeight = parseInt(window.getComputedStyle(dragItem).height, 10); function doResize(e) { bonkHUD.resizeMove(e, startX, startY, windowX, windowY, startWidth, startHeight, dragItem, dir); } function stopResizing() { bonkHUD.resizeEnd(doResize, dragItem, ind); } document.addEventListener('mousemove', doResize); document.addEventListener('mouseup', stopResizing, { once: true }); }; // Function to handle the resize event bonkHUD.resizeMove = function (e, startX, startY, windowX, windowY, startWidth, startHeight, dragItem, dir) { let newWidth = 0; let newHeight = 0; if(dir == "nw") { newWidth = startWidth - (e.clientX - startX); newHeight = startHeight - (e.clientY - startY); dragItem.style.height = bonkHUD.pxTorem(Math.max(30, newHeight)) + 'rem'; dragItem.style.width = bonkHUD.pxTorem(Math.max(154, newWidth)) + 'rem'; } else if(dir == "sw") { newWidth = startWidth - (e.clientX - startX); newHeight = startHeight + (e.clientY - startY); dragItem.style.height = bonkHUD.pxTorem(Math.max(30, newHeight)) + 'rem'; dragItem.style.bottom = bonkHUD.pxTorem(windowY - (newHeight < 30 ? 30 - startHeight : e.clientY - startY)) + 'rem'; dragItem.style.width = bonkHUD.pxTorem(Math.max(154, newWidth)) + 'rem'; } else if(dir == "ne") { newWidth = startWidth + (e.clientX - startX); newHeight = startHeight - (e.clientY - startY); dragItem.style.height = bonkHUD.pxTorem(Math.max(30, newHeight)) + 'rem'; dragItem.style.width = bonkHUD.pxTorem(Math.max(154, newWidth)) + 'rem'; dragItem.style.right = bonkHUD.pxTorem(windowX - (newWidth < 154 ? 154 - startWidth : e.clientX - startX)) + 'rem'; } else { newWidth = startWidth + (e.clientX - startX); newHeight = startHeight + (e.clientY - startY); dragItem.style.height = bonkHUD.pxTorem(Math.max(30, newHeight)) + 'rem'; dragItem.style.bottom = bonkHUD.pxTorem(windowY - (newHeight < 30 ? 30 - startHeight : e.clientY - startY)) + 'rem'; dragItem.style.width = bonkHUD.pxTorem(Math.max(154, newWidth)) + 'rem'; dragItem.style.right = bonkHUD.pxTorem(windowX - (newWidth < 154 ? 154 - startWidth : e.clientX - startX)) + 'rem'; } }; // Function to stop the resize event bonkHUD.resizeEnd = function (resizeMoveFn, dragItem, ind) { document.removeEventListener('mousemove', resizeMoveFn); //let ind = bonkHUD.getWindowIndexByID(dragItem.id.substring(0, dragItem.id.length - 5)); bonkHUD.windowHold[ind].width = dragItem.style.width; bonkHUD.windowHold[ind].height = dragItem.style.height; bonkHUD.windowHold[ind].bottom = dragItem.style.bottom; bonkHUD.windowHold[ind].right = dragItem.style.right; bonkHUD.saveUISetting(ind); }; bonkHUD.saveStyleSettings = function () { localStorage.setItem('bonkHUD_Style_Settings', JSON.stringify(bonkHUD.styleHold)); }; bonkHUD.exportStyleSettings = function() { let exportStyleHold = []; for(let prop in bonkHUD.styleHold) { exportStyleHold.push(bonkHUD.styleHold[prop].color); } let out = JSON.stringify(exportStyleHold); let save = new File([out], "bonkHUDStyle-" + Date.now() + ".style", {type: 'text/plain',}); let url = URL.createObjectURL(save); let link = document.createElement("a"); link.href = url; link.download = save.name; document.body.appendChild(link); link.click(); document.body.removeChild(link); window.URL.revokeObjectURL(url); } bonkHUD.importStyleSettings = function(event) { if(!event || !event.target || !event.target.files || event.target.files.length === 0) { return; } let fileReader = new FileReader(); fileReader.addEventListener("load", (e) => { let tempStyleHold = {}; try { let temp = JSON.parse(e.target.result); let i = 0; for(let prop in bonkHUD.styleHold) { tempStyleHold[prop] = {}; tempStyleHold[prop].class = bonkHUD.styleHold[prop].class; tempStyleHold[prop].css = bonkHUD.styleHold[prop].css; if(typeof temp[i] == "string" && temp[i].charAt(0) === "#" && !isNaN(Number("0x" + temp[i].substring(1, 7)))) { tempStyleHold[prop].color = temp[i]; } else { throw new Error("Incorrect style input"); } i++; } bonkHUD.loadStyleSettings(tempStyleHold); bonkHUD.updateStyleSettings(); bonkHUD.saveStyleSettings(); } catch (er) { alert(er); } }, false); //let file = event.target.files[0]; fileReader.readAsText(event.target.files[0]); } bonkHUD.loadStyleSettings = function (settings) { if(!settings) { settings = JSON.parse(localStorage.getItem('bonkHUD_Style_Settings')); } if (settings) { bonkHUD.styleHold = {}; for (let prop in settings) { bonkHUD.styleHold[prop] = settings[prop]; } } else { bonkHUD.resetStyleSettings(); } }; bonkHUD.resetStyleSettings = function () { localStorage.removeItem('bonkHUD_Style_Settings'); //Add bonkhud to key for class name bonkHUD.styleHold = { backgroundColor: {class:"bonkhud-background-color", css:"background-color", color:"#cfd8cd"}, borderColor: {class:"bonkhud-border-color", css:"border-color", color:"#b4b8ae"}, headerColor: {class:"bonkhud-header-color", css:"background-color", color:"#009688"}, titleColor: {class:"bonkhud-title-color", css:"color", color:"#ffffff"}, textColor: {class:"bonkhud-text-color", css:"color", color:"#000000"}, secondaryTextColor: {class:"bonkhud-secondary-text-color", css:"color", color:"#505050"}, buttonColor: {class:"bonkhud-button-color", css:"background-color", color:"#bcc4bb"}, buttonColorHover: {class:"bonkhud-button-color-hover", css:"background-color", color:"#acb9ad"}, }; }; bonkHUD.updateStyleSettings = function () { for(let prop in bonkHUD.styleHold) { try { let colorEdit = document.getElementById("bonkhud-" + prop + "-edit"); colorEdit.value = bonkHUD.styleHold[prop].color; } catch (er) { console.log("Element bonkhud-" + prop + "-edit does not exist"); } if(prop == "buttonColorHover") continue; else if(prop == "headerColor") { let elements = document.getElementsByClassName(bonkHUD.styleHold[prop].class); for (let j = 0; j < elements.length; j++) { elements[j].style.setProperty(bonkHUD.styleHold[prop].css, bonkHUD.styleHold[prop].color, "important"); } continue; } else { let elements = document.getElementsByClassName(bonkHUD.styleHold[prop].class); for (let j = 0; j < elements.length; j++) { elements[j].style.setProperty(bonkHUD.styleHold[prop].css, bonkHUD.styleHold[prop].color); } } } }; bonkHUD.saveUISetting = function (ind) { let save_id = 'bonkHUD_Setting_' + bonkHUD.windowHold[ind].id; localStorage.setItem(save_id, JSON.stringify(bonkHUD.windowHold[ind])); }; bonkHUD.getUISetting = function (ind) { let save_id = 'bonkHUD_Setting_' + bonkHUD.windowHold[ind].id; let setting = JSON.parse(localStorage.getItem(save_id)); if (!setting) { setting = { id: bonkHUD.windowHold[ind].id, width: "154px", height: "100px", bottom: "0rem", right: "0rem", opacity: "1", display: "block", } } return setting; }; bonkHUD.loadUISetting = function (ind) { let windowElement = document.getElementById(bonkHUD.windowHold[ind].id + "-drag"); if (windowElement) { Object.assign(windowElement.style, bonkHUD.getUISetting(ind)); } else { console.log(`bonkHUD.loadUISetting: Window element not found for id: ${bonkHUD.windowHold[ind].id}. Please ensure the window has been created.`); } }; bonkHUD.resetUISetting = function (ind) { let windowElement = document.getElementById(bonkHUD.windowHold[ind].id + "-drag"); if (windowElement) { let save_id = 'bonkHUD_Setting_' + bonkHUD.windowHold[ind].id; localStorage.removeItem(save_id); Object.assign(windowElement.style, bonkHUD.getUISetting(ind)); } else { console.log(`bonkHUD.resetUISetting: Window element not found for id: ${bonkHUD.windowHold[ind].id}. Please ensure the window has been created.`); } }; //! Eventually change ID to Id bonkHUD.getWindowIndexByID = function (id) { for (let i = 0; i < bonkHUD.windowHold.length; i++) { if (bonkHUD.windowHold[i].id == id) { return i; } } return -1; }; bonkHUD.getWindowIdByIndex = function (ind) { return bonkHUD.windowHold[ind].id } bonkHUD.getElementByIndex = function (ind) { return document.getElementById(bonkHUD.windowHold[ind].id) } bonkHUD.clamp = function (val, min, max) { //? supposedly faster than Math.max/min if (val > min) { if (val < max) { return val; } else { return max; } } return min; }; bonkHUD.pxTorem = function (px) { return px / parseFloat(getComputedStyle(document.documentElement).fontSize); }; bonkHUD.remTopx = function (rem) { return rem * parseFloat(getComputedStyle(document.documentElement).fontSize); }; bonkHUD.generateButton = function (name) { let newButton = document.createElement("div"); newButton.classList.add("bonkhud-button-color"); newButton.classList.add("bonkhud-text-color"); newButton.style.cursor = "pointer"; newButton.style.borderRadius = "3px"; newButton.style.textAlign = "center"; newButton.style.backgroundColor = bonkHUD.styleHold.buttonColor.color; newButton.innerText = name; newButton.addEventListener('mouseover', (e) => { e.target.style.backgroundColor = bonkHUD.styleHold.buttonColorHover.color; }); newButton.addEventListener('mouseleave', (e) => { e.target.style.backgroundColor = bonkHUD.styleHold.buttonColor.color; }); return newButton; } bonkHUD.generateSection = function () { let sliderRow = document.createElement("div"); sliderRow.classList.add("bonkhud-settings-row"); sliderRow.classList.add("bonkhud-border-color"); return sliderRow; } bonkHUD.initialize = function () { //bonkHUD.stylesheet = document.createElement("style"); let settingsMenu = document.createElement("div"); settingsMenu.id = "bonkhud-settings"; settingsMenu.classList.add("bonkhud-background-color"); settingsMenu.classList.add("windowShadow"); settingsMenu.style.position = "absolute"; settingsMenu.style.top = "0"; settingsMenu.style.left = "0"; settingsMenu.style.right = "0"; settingsMenu.style.bottom = "0"; settingsMenu.style.width = "60%";//bonkHUD.pxTorem(450) + "rem"; settingsMenu.style.height = "75%";//bonkHUD.pxTorem(385) + "rem"; settingsMenu.style.fontFamily = "futurept_b1"; settingsMenu.style.margin = "auto"; settingsMenu.style.borderRadius = "8px"; //settingsMenu.style.outline = "3000px solid rgba(0,0,0,0.30)"; settingsMenu.style.pointerEvents = "auto"; settingsMenu.style.zIndex = "9992"; settingsMenu.style.visibility = "hidden"; // Create the header let header = document.createElement("div"); header.classList.add("newbonklobby_boxtop"); header.classList.add("newbonklobby_boxtop_classic"); header.classList.add("bonkhud-header-color"); // Create the title span let title = document.createElement("span"); title.classList.add("bonkhud-title-color"); title.textContent = "BonkHUD Settings"; title.style.flexGrow = "1"; title.style.textAlign = "center"; let closeButton = document.createElement("div"); closeButton.classList.add("bonkhud-header-button"); closeButton.classList.add("bonkhud-title-color"); closeButton.innerText = "_"; // Use an appropriate icon or text closeButton.style.lineHeight = "9px"; closeButton.style.right = "3px"; closeButton.style.cursor = "pointer"; let containerContainer = document.createElement("div"); containerContainer.classList.add("bonkhud-text-color"); containerContainer.style.overflowX = "hidden"; containerContainer.style.overflowY = "hidden"; containerContainer.style.display = "flex"; containerContainer.style.width = "100%"; containerContainer.style.height = "calc(100% - 32px)"; // Adjusted height for header let windowSettingsContainer = document.createElement("div"); windowSettingsContainer.id = "bonkhud-window-settings-container"; windowSettingsContainer.classList.add("bonkhud-border-color"); windowSettingsContainer.classList.add("bonkhud-scrollbar-kit"); windowSettingsContainer.classList.add("bonkhud-scrollbar-other"); windowSettingsContainer.style.width = "35%"; windowSettingsContainer.style.overflowY = "scroll"; windowSettingsContainer.style.height = "100%"; windowSettingsContainer.style.borderRight = "1px solid"; let settingsContainer = document.createElement("div"); settingsContainer.classList.add("bonkhud-scrollbar-kit"); settingsContainer.classList.add("bonkhud-scrollbar-other"); settingsContainer.id = "bonkhud-settings-container"; settingsContainer.style.overflowY = "scroll"; settingsContainer.style.width = "65%"; settingsContainer.style.float = "right"; settingsContainer.style.height = "100%"; // Create holder for mainSettings and styleSettings let generalSettingsDiv = document.createElement("div"); let mainSettingsDiv = document.createElement("div"); mainSettingsDiv.classList.add("bonkhud-border-color") mainSettingsDiv.classList.add("bonkhud-settings-row"); let mainSettingsHeading = document.createElement("div"); mainSettingsHeading.classList.add("bonkhud-text-color"); mainSettingsHeading.style.fontSize = "1.2rem"; mainSettingsHeading.style.marginBottom = "5px"; mainSettingsHeading.textContent = "Main Settings"; let mainSettingsAdHideLabel = document.createElement("label"); mainSettingsAdHideLabel.classList.add("bonkhud-text-color"); mainSettingsAdHideLabel.classList.add("bonkhud-settings-label"); mainSettingsAdHideLabel.style.marginRight = "5px"; mainSettingsAdHideLabel.innerText = "Hide Ads"; let mainSettingsAdHide = document.createElement("input"); mainSettingsAdHide.type = "checkbox"; mainSettingsAdHide.checked = false; let styleResetDiv = document.createElement("div"); styleResetDiv.style.marginTop = "5px"; let styleResetLabel = document.createElement("label"); styleResetLabel.classList.add("bonkhud-text-color"); styleResetLabel.classList.add("bonkhud-settings-label"); styleResetLabel.style.marginRight = "5px"; styleResetLabel.innerText = "Reset Style"; let styleResetButton = bonkHUD.generateButton("Reset"); styleResetButton.style.paddingLeft = "5px"; styleResetButton.style.paddingRight = "5px"; styleResetButton.style.display = "inline-block"; let styleExportDiv = document.createElement("div"); styleExportDiv.style.marginTop = "5px"; let styleExportLabel = document.createElement("label"); styleExportLabel.classList.add("bonkhud-text-color"); styleExportLabel.classList.add("bonkhud-settings-label"); styleExportLabel.style.marginRight = "5px"; styleExportLabel.innerText = "Export Style"; let styleExportButton = bonkHUD.generateButton("Export"); styleExportButton.style.paddingLeft = "5px"; styleExportButton.style.paddingRight = "5px"; styleExportButton.style.display = "inline-block"; let styleImportDiv = document.createElement("div"); styleImportDiv.style.marginTop = "5px"; let styleImportLabel = document.createElement("label"); styleImportLabel.classList.add("bonkhud-text-color"); styleImportLabel.classList.add("bonkhud-settings-label"); styleImportLabel.style.marginRight = "5px"; styleImportLabel.innerText = "Import Style"; let styleImportButton = bonkHUD.generateButton("Import"); styleImportButton.style.paddingLeft = "5px"; styleImportButton.style.paddingRight = "5px"; styleImportButton.style.display = "inline-block"; let styleImportInput = document.createElement("input"); styleImportInput.setAttribute("type", "file"); styleImportInput.setAttribute("accept", ".style"); styleImportInput.setAttribute("multiple", ""); styleImportInput.setAttribute("onChange", "bonkHUD.importStyleSettings(event);this.value=null"); styleImportInput.style.display = "none"; let styleSettingsDiv = document.createElement("div"); styleSettingsDiv.classList.add("bonkhud-border-color") styleSettingsDiv.classList.add("bonkhud-settings-row"); let styleSettingsHeading = document.createElement("div"); styleSettingsHeading.classList.add("bonkhud-text-color"); styleSettingsHeading.style.fontSize = "1.2rem"; styleSettingsHeading.style.marginBottom = "5px"; styleSettingsHeading.textContent = "Style Settings"; mainSettingsDiv.appendChild(mainSettingsHeading); mainSettingsDiv.appendChild(mainSettingsAdHideLabel); mainSettingsDiv.appendChild(mainSettingsAdHide); // Append children of style settings to rows styleResetDiv.appendChild(styleResetLabel); styleResetDiv.appendChild(styleResetButton); styleExportDiv.appendChild(styleExportLabel); styleExportDiv.appendChild(styleExportButton); styleImportDiv.appendChild(styleImportLabel); styleImportDiv.appendChild(styleImportButton); styleImportDiv.appendChild(styleImportInput); styleSettingsDiv.appendChild(styleSettingsHeading); styleSettingsDiv.appendChild(styleResetDiv); styleSettingsDiv.appendChild(styleExportDiv) styleSettingsDiv.appendChild(styleImportDiv); let holdLeft = document.createElement("div"); holdLeft.style.display = "flex"; holdLeft.style.alignContent = "center"; let opacityLabel = document.createElement("label"); opacityLabel.classList.add("bonkhud-settings-label"); opacityLabel.textContent = "Opacity"; let opacitySlider = document.createElement("input"); opacitySlider.type = "range"; // Slider type for range selection opacitySlider.min = "0.1"; // Minimum opacity value opacitySlider.max = "1"; // Maximum opacity value (fully opaque) opacitySlider.step = "0.05"; // Incremental steps for opacity adjustment opacitySlider.value = "1"; // Default value set to fully opaque opacitySlider.style.minWidth = "20px"; opacitySlider.style.flexGrow = "1"; // Width adjusted for the label holdLeft.appendChild(opacityLabel); holdLeft.appendChild(opacitySlider); styleSettingsDiv.appendChild(holdLeft); for (let prop in bonkHUD.styleHold) { let colorDiv = document.createElement("div"); colorDiv.style.marginTop="5px"; let colorLabel = document.createElement("label"); colorLabel.classList.add("bonkhud-text-color"); colorLabel.classList.add("bonkhud-settings-label"); colorLabel.style.marginRight = "10px"; colorLabel.innerText = bonkHUD.styleHold[prop].class; let colorEdit = document.createElement("input"); colorEdit.setAttribute('type', 'color'); colorEdit.id = "bonkhud-" + prop + "-edit"; colorEdit.value = bonkHUD.styleHold[prop].color; colorEdit.style.display = "inline-block"; colorDiv.appendChild(colorLabel); colorDiv.appendChild(colorEdit); styleSettingsDiv.appendChild(colorDiv); colorEdit.addEventListener('change', (e) => { bonkHUD.styleHold[prop].color = e.target.value; bonkHUD.saveStyleSettings(); bonkHUD.updateStyleSettings(); }); } let topBarButtons = document.querySelectorAll("#pretty_top_bar > .niceborderleft"); //Create element in top bar let topBarOption = document.createElement("div"); topBarOption.style.width = "58px"; topBarOption.style.height = "34px"; topBarOption.style.backgroundRepeat = "no-repeat"; topBarOption.style.backgroundPosition = "center"; topBarOption.style.position = "absolute"; topBarOption.style.right = topBarButtons.length * 58 + 1 + "px"; topBarOption.style.top = "0"; topBarOption.style.visibility = "visible"; topBarOption.style.borderBottom = "2px solid transparent"; topBarOption.style.lineHeight = "34px"; topBarOption.style.textAlign = "center"; topBarOption.style.fontFamily = "futurept_b1"; topBarOption.style.color = "#ffffff"; topBarOption.classList.add("niceborderleft"); topBarOption.classList.add("pretty_top_button"); let topBarIcon = document.createElement("span"); topBarIcon.innerText = "HUD"; // Append Header header.appendChild(title); header.appendChild(closeButton) // Append everything to main container (HUD window) containerContainer.appendChild(windowSettingsContainer); containerContainer.appendChild(settingsContainer); settingsMenu.appendChild(header); settingsMenu.appendChild(containerContainer); topBarOption.appendChild(topBarIcon); document.getElementById('prettymenu').appendChild(settingsMenu); //Place it before help button document.getElementById('pretty_top_bar').appendChild(topBarOption); // Add settings bonkHUD.createSettingsControl(mainSettingsDiv, generalSettingsDiv); bonkHUD.createSettingsControl(styleSettingsDiv, generalSettingsDiv); bonkHUD.createMenuHeader("General", generalSettingsDiv); let ind = bonkHUD.settingsHold.length; bonkHUD.settingsHold.push("bonkhud-main-mod-setting"); let settings = { hideAds: false, opacity: "1"}; let tempSettings = bonkHUD.getModSetting(ind); if (tempSettings != null) { settings = tempSettings; // Could bring into one function then call it mainSettingsAdHide.checked = settings.hideAds; let ad1 = window.top.document.getElementById('adboxverticalCurse'); let ad2 = window.top.document.getElementById('adboxverticalleftCurse'); if (settings.hideAds) { ad1.style.display = "none"; ad2.style.display = "none"; } else { ad1.style.display = "block"; ad2.style.display = "block"; } opacitySlider.value = settings.opacity; settingsMenu.style.opacity = settings.opacity; } opacitySlider.oninput = function () { settingsMenu.style.opacity = this.value; settings.opacity = this.value; bonkHUD.saveModSetting(ind, settings); }; mainSettingsAdHide.oninput = function () { settings.hideAds = this.checked; let ad1 = window.top.document.getElementById('adboxverticalCurse'); let ad2 = window.top.document.getElementById('adboxverticalleftCurse'); if (settings.hideAds) { ad1.style.display = "none"; ad2.style.display = "none"; } else { ad1.style.display = "block"; ad2.style.display = "block"; } bonkHUD.saveModSetting(ind, settings); } // Make menu to control opacity + visibility visible closeButton.addEventListener('click', (e) => { settingsMenu.style.visibility = "hidden"; }) topBarOption.addEventListener('click', (e) => { if (settingsMenu.style.visibility == "hidden") { settingsMenu.style.visibility = "visible"; } else { settingsMenu.style.visibility = "hidden"; } }); styleResetButton.addEventListener('click', (e) => { bonkHUD.resetStyleSettings(); bonkHUD.updateStyleSettings(); }); styleExportButton.addEventListener('click', (e) => { bonkHUD.updateStyleSettings(); bonkHUD.exportStyleSettings(); }); styleImportButton.addEventListener('click', (e) => { styleImportInput.click(); }); }; bonkHUD.createMenuHeader = function (name, settingsContent, recVersion = -1) { // Create container for the opacity controls with initial styles let sliderRow = bonkHUD.generateSection(); // Add a title to the slider row for visual clarity let sliderTitle = document.createElement("div"); if (recVersion === -1) { sliderTitle.textContent = name; } else { sliderTitle.textContent = name + " ("+recVersion+")"; } sliderTitle.style.marginBottom = "5px"; sliderTitle.style.fontSize = "1.2rem"; // Text size for readability sliderTitle.style.fontWeight = "bold"; // Make the title text bold sliderRow.appendChild(sliderTitle); // Insert the title into the slider container //open settings in settingsContent.prepend(sliderRow.cloneNode(true)); settingsContent.classList.add("bonkhud-mod-setting-menu"); settingsContent.style.display = "none"; document.getElementById("bonkhud-settings-container").appendChild(settingsContent); sliderRow.addEventListener("click", (e) => { let menus = document.getElementsByClassName("bonkhud-mod-setting-menu"); // Could make this without for loop but would need to store last menu for (let i = 0; i < menus.length; i++) { menus[i].style.display = "none"; } settingsContent.style.display = "block"; let titles = document.getElementById("bonkhud-window-settings-container").children; for (let i = 0; i < titles.length; i++) { titles[i].children[0].style.color = bonkHUD.styleHold.textColor.color; } sliderTitle.style.color = bonkHUD.styleHold.secondaryTextColor.color; }); document.getElementById("bonkhud-window-settings-container").appendChild(sliderRow); } bonkHUD.createWindowControl = function (ind, element) { let sliderRow = bonkHUD.generateSection(); let holdLeft = document.createElement("div"); holdLeft.style.display = "flex"; holdLeft.style.alignContent = "center"; // Create a label for the opacity slider for accessibility let opacityLabel = document.createElement("label"); opacityLabel.classList.add("bonkhud-settings-label"); opacityLabel.textContent = "Opacity"; holdLeft.appendChild(opacityLabel); // Add the label to the slider container // Create the opacity slider input, configuring its range and appearance let opacitySlider = document.createElement("input"); opacitySlider.type = "range"; // Slider type for range selection opacitySlider.min = "0.1"; // Minimum opacity value opacitySlider.max = "1"; // Maximum opacity value (fully opaque) opacitySlider.step = "0.05"; // Incremental steps for opacity adjustment opacitySlider.value = bonkHUD.windowHold[ind].opacity; // Default value set to fully opaque opacitySlider.style.minWidth = "20px"; opacitySlider.style.flexGrow = "1"; // Width adjusted for the label opacitySlider.oninput = function () { let control = document.getElementById(bonkHUD.windowHold[ind].id + "-drag"); // Update the UI opacity in real-time; control.style.opacity = this.value; bonkHUD.windowHold[ind].opacity = control.style.opacity; bonkHUD.saveUISetting(ind); }; holdLeft.appendChild(opacitySlider); // Place the slider into the slider container let holdRight = document.createElement("div"); let visibilityLabel = document.createElement("label"); visibilityLabel.classList.add("bonkhud-settings-label"); visibilityLabel.textContent = "Visible"; visibilityLabel.style.marginRight = "5px"; // Space between label and slider visibilityLabel.style.display = "inline-block"; // Allows margin-top adjustment visibilityLabel.style.verticalAlign = "middle"; holdRight.appendChild(visibilityLabel); let visiblityCheck = document.createElement("input"); visiblityCheck.id = bonkHUD.windowHold[ind].id + "-visibility-check"; visiblityCheck.type = "checkbox"; // Slider type for range selection if (bonkHUD.windowHold[ind].display == "block") { visiblityCheck.checked = true; } else { visiblityCheck.checked = false; } visiblityCheck.style.display = "inline-block"; // Allows margin-top adjustment visiblityCheck.style.verticalAlign = "middle"; visiblityCheck.oninput = function () { let control = document.getElementById(bonkHUD.windowHold[ind].id + "-drag"); // Update the UI opacity in real-time; control.style.display = this.checked ? "block" : "none"; bonkHUD.windowHold[ind].display = control.style.display; bonkHUD.saveUISetting(ind); }; holdRight.appendChild(visiblityCheck); // Place the slider into the slider container let windowResetButton = bonkHUD.generateButton("Reset"); windowResetButton.style.paddingLeft = "5px"; windowResetButton.style.paddingRight = "5px"; windowResetButton.style.display = "inline-block"; windowResetButton.addEventListener('click', (e) => { bonkHUD.resetUISetting(ind); bonkHUD.loadUISetting(ind); }); sliderRow.appendChild(holdLeft); sliderRow.appendChild(holdRight); sliderRow.appendChild(windowResetButton); element.appendChild(sliderRow); //bonkHUD.settingsHold[ind].settings.appendChild(sliderRow); }; bonkHUD.focusWindow = function (focusItem) { let elements = document.getElementsByClassName("bonkhud-window-container"); focusItem.style.zIndex = "9991"; for (let i = 0; i < elements.length; i++) { if (focusItem.id != elements[i].id) { elements[i].style.zIndex = "9990"; } } }; //!------------------Load Complete Detection------------------ bonkLIB.onLoaded = () => { bonkAPI.originalDrawShape = window.PIXI.Graphics.prototype.drawShape; bonkAPI.pixiCtx = new window.PIXI.Container(); // !Map Decoder bonkAPI.LZString = window.LZString; bonkAPI.PSON = window.dcodeIO.PSON; bonkAPI.bytebuffer = window.dcodeIO.ByteBuffer; bonkAPI.textdecoder = new window.TextDecoder(); bonkAPI.textencoder = new window.TextEncoder(); bonkAPI.ISpsonpair = new window.dcodeIO.PSON.StaticPair([ "physics", "shapes", "fixtures", "bodies", "bro", "joints", "ppm", "lights", "spawns", "lasers", "capZones", "type", "w", "h", "c", "a", "v", "l", "s", "sh", "fr", "re", "de", "sn", "fc", "fm", "f", "d", "n", "bg", "lv", "av", "ld", "ad", "fr", "bu", "cf", "rv", "p", "d", "bf", "ba", "bb", "aa", "ab", "axa", "dr", "em", "mmt", "mms", "ms", "ut", "lt", "New body", "Box Shape", "Circle Shape", "Polygon Shape", "EdgeChain Shape", "priority", "Light", "Laser", "Cap Zone", "BG Shape", "Background Layer", "Rotate Joint", "Slider Joint", "Rod Joint", "Gear Joint", 65535, 16777215, ]); class bonkAPI_bytebuffer { constructor() { var g1d = [arguments]; this.index = 0; this.buffer = new ArrayBuffer(100*1024); this.view = new DataView(this.buffer); this.implicitClassAliasArray = []; this.implicitStringArray = []; this.bodgeCaptureZoneDataIdentifierArray = []; } readByte() { var N0H = [arguments]; N0H[4] = this.view.getUint8(this.index); this.index += 1; return N0H[4]; } writeByte(z0w) { var v8$ = [arguments]; this.view.setUint8(this.index, v8$[0][0]); this.index += 1; } readInt() { var A71 = [arguments]; A71[6] = this.view.getInt32(this.index); this.index += 4; return A71[6]; } writeInt(W6i) { var p5u = [arguments]; this.view.setInt32(this.index, p5u[0][0]); this.index += 4; } readShort() { var R1R = [arguments]; R1R[9] = this.view.getInt16(this.index); this.index += 2; return R1R[9]; } writeShort(H8B) { var d_3 = [arguments]; this.view.setInt16(this.index, d_3[0][0]); this.index += 2; } readUint() { var W2$ = [arguments]; W2$[8] = this.view.getUint32(this.index); this.index += 4; return W2$[8]; } writeUint(B2X) { var f8B = [arguments]; this.view.setUint32(this.index, f8B[0][0]); this.index += 4; } readBoolean() { var h6P = [arguments]; h6P[6] = this.readByte(); return h6P[6] == 1; } writeBoolean(Y3I) { var l79 = [arguments]; if (l79[0][0]) { this.writeByte(1); } else { this.writeByte(0); } } readDouble() { var V60 = [arguments]; V60[4] = this.view.getFloat64(this.index); this.index += 8; return V60[4]; } writeDouble(z4Z) { var O41 = [arguments]; this.view.setFloat64(this.index, O41[0][0]); this.index += 8; } readFloat() { var I0l = [arguments]; I0l[5] = this.view.getFloat32(this.index); this.index += 4; return I0l[5]; } writeFloat(y4B) { var B0v = [arguments]; this.view.setFloat32(this.index, B0v[0][0]); this.index += 4; } readUTF() { var d6I = [arguments]; d6I[8] = this.readByte(); d6I[7] = this.readByte(); d6I[9] = d6I[8] * 256 + d6I[7]; d6I[1] = new Uint8Array(d6I[9]); for (d6I[6] = 0; d6I[6] < d6I[9]; d6I[6]++) { d6I[1][d6I[6]] = this.readByte(); } return bonkAPI.textdecoder.decode(d6I[1]); } writeUTF(L3Z) { var Z75 = [arguments]; Z75[4] = bonkAPI.textencoder.encode(Z75[0][0]); Z75[3] = Z75[4].length; Z75[5] = Math.floor(Z75[3]/256); Z75[8] = Z75[3] % 256; this.writeByte(Z75[5]); this.writeByte(Z75[8]); Z75[7] = this; Z75[4].forEach(I_O); function I_O(s0Q, H4K, j$o) { var N0o = [arguments]; Z75[7].writeByte(N0o[0][0]); } } toBase64() { var P4$ = [arguments]; P4$[4] = ""; P4$[9] = new Uint8Array(this.buffer); P4$[8] = this.index; for (P4$[7] = 0; P4$[7] < P4$[8]; P4$[7]++) { P4$[4] += String.fromCharCode(P4$[9][P4$[7]]); } return window.btoa(P4$[4]); } fromBase64(W69, A8Q) { var o0n = [arguments]; o0n[8] = window.pako; o0n[6] = window.atob(o0n[0][0]); o0n[9] = o0n[6].length; o0n[4] = new Uint8Array(o0n[9]); for (o0n[1] = 0; o0n[1] < o0n[9]; o0n[1]++) { o0n[4][o0n[1]] = o0n[6].charCodeAt(o0n[1]); } if (o0n[0][1] === true) { o0n[5] = o0n[8].inflate(o0n[4]); o0n[4] = o0n[5]; } this.buffer = o0n[4].buffer.slice( o0n[4].byteOffset, o0n[4].byteLength + o0n[4].byteOffset ); this.view = new DataView(this.buffer); this.index = 0; } } bonkAPI.ISdecode = function (rawdata) { rawdata_caseflipped = ""; for (i = 0; i < rawdata.length; i++) { if (i <= 100 && rawdata.charAt(i) === rawdata.charAt(i).toLowerCase()) { rawdata_caseflipped += rawdata.charAt(i).toUpperCase(); } else if (i <= 100 && rawdata.charAt(i) === rawdata.charAt(i).toUpperCase()) { rawdata_caseflipped += rawdata.charAt(i).toLowerCase(); } else { rawdata_caseflipped += rawdata.charAt(i); } } data_deLZd = bonkAPI.LZString.decompressFromEncodedURIComponent(rawdata_caseflipped); databuffer = bonkAPI.bytebuffer.fromBase64(data_deLZd); data = bonkAPI.ISpsonpair.decode(databuffer.buffer); return data; }; bonkAPI.ISencode = function (obj) { data = bonkAPI.ISpsonpair.encode(obj); b64 = data.toBase64(); lzd = bonkAPI.LZString.compressToEncodedURIComponent(b64); caseflipped = ""; for (i = 0; i < lzd.length; i++) { if (i <= 100 && lzd.charAt(i) === lzd.charAt(i).toLowerCase()) { caseflipped += lzd.charAt(i).toUpperCase(); } else if (i <= 100 && lzd.charAt(i) === lzd.charAt(i).toUpperCase()) { caseflipped += lzd.charAt(i).toLowerCase(); } else { caseflipped += lzd.charAt(i); } } return caseflipped; }; bonkAPI.decodeIS = function (x) { return bonkAPI.ISdecode(x); }; bonkAPI.encodeIS = function (x) { return bonkAPI.ISencode(x); }; bonkAPI.encodeMap = function (W2A) { var M3n = [arguments]; M3n[1] = new bonkAPI_bytebuffer(); M3n[9] = M3n[0][0].physics; M3n[0][0].v = 15; M3n[1].writeShort(M3n[0][0].v); M3n[1].writeBoolean(M3n[0][0].s.re); M3n[1].writeBoolean(M3n[0][0].s.nc); M3n[1].writeShort(M3n[0][0].s.pq); M3n[1].writeFloat(M3n[0][0].s.gd); M3n[1].writeBoolean(M3n[0][0].s.fl); M3n[1].writeUTF(M3n[0][0].m.rxn); M3n[1].writeUTF(M3n[0][0].m.rxa); M3n[1].writeUint(M3n[0][0].m.rxid); M3n[1].writeShort(M3n[0][0].m.rxdb); M3n[1].writeUTF(M3n[0][0].m.n); M3n[1].writeUTF(M3n[0][0].m.a); M3n[1].writeUint(M3n[0][0].m.vu); M3n[1].writeUint(M3n[0][0].m.vd); M3n[1].writeShort(M3n[0][0].m.cr.length); for (M3n[84] = 0; M3n[84] < M3n[0][0].m.cr.length; M3n[84]++) { M3n[1].writeUTF(M3n[0][0].m.cr[M3n[84]]); } M3n[1].writeUTF(M3n[0][0].m.mo); M3n[1].writeInt(M3n[0][0].m.dbid); M3n[1].writeBoolean(M3n[0][0].m.pub); M3n[1].writeInt(M3n[0][0].m.dbv); M3n[1].writeShort(M3n[9].ppm); M3n[1].writeShort(M3n[9].bro.length); for (M3n[17] = 0; M3n[17] < M3n[9].bro.length; M3n[17]++) { M3n[1].writeShort(M3n[9].bro[M3n[17]]); } M3n[1].writeShort(M3n[9].shapes.length); for (M3n[80] = 0; M3n[80] < M3n[9].shapes.length; M3n[80]++) { M3n[2] = M3n[9].shapes[M3n[80]]; if (M3n[2].type == "bx") { M3n[1].writeShort(1); M3n[1].writeDouble(M3n[2].w); M3n[1].writeDouble(M3n[2].h); M3n[1].writeDouble(M3n[2].c[0]); M3n[1].writeDouble(M3n[2].c[1]); M3n[1].writeDouble(M3n[2].a); M3n[1].writeBoolean(M3n[2].sk); } if (M3n[2].type == "ci") { M3n[1].writeShort(2); M3n[1].writeDouble(M3n[2].r); M3n[1].writeDouble(M3n[2].c[0]); M3n[1].writeDouble(M3n[2].c[1]); M3n[1].writeBoolean(M3n[2].sk); } if (M3n[2].type == "po") { M3n[1].writeShort(3); M3n[1].writeDouble(M3n[2].s); M3n[1].writeDouble(M3n[2].a); M3n[1].writeDouble(M3n[2].c[0]); M3n[1].writeDouble(M3n[2].c[1]); M3n[1].writeShort(M3n[2].v.length); for (M3n[61] = 0; M3n[61] < M3n[2].v.length; M3n[61]++) { M3n[1].writeDouble(M3n[2].v[M3n[61]][0]); M3n[1].writeDouble(M3n[2].v[M3n[61]][1]); } } } M3n[1].writeShort(M3n[9].fixtures.length); for (M3n[20] = 0; M3n[20] < M3n[9].fixtures.length; M3n[20]++) { M3n[7] = M3n[9].fixtures[M3n[20]]; M3n[1].writeShort(M3n[7].sh); M3n[1].writeUTF(M3n[7].n); if (M3n[7].fr === null) { M3n[1].writeDouble(Number.MAX_VALUE); } else { M3n[1].writeDouble(M3n[7].fr); } if (M3n[7].fp === null) { M3n[1].writeShort(0); } if (M3n[7].fp === false) { M3n[1].writeShort(1); } if (M3n[7].fp === true) { M3n[1].writeShort(2); } if (M3n[7].re === null) { M3n[1].writeDouble(Number.MAX_VALUE); } else { M3n[1].writeDouble(M3n[7].re); } if (M3n[7].de === null) { M3n[1].writeDouble(Number.MAX_VALUE); } else { M3n[1].writeDouble(M3n[7].de); } M3n[1].writeUint(M3n[7].f); M3n[1].writeBoolean(M3n[7].d); M3n[1].writeBoolean(M3n[7].np); M3n[1].writeBoolean(M3n[7].ng); M3n[1].writeBoolean(M3n[7].ig); } M3n[1].writeShort(M3n[9].bodies.length); for (M3n[37] = 0; M3n[37] < M3n[9].bodies.length; M3n[37]++) { M3n[4] = M3n[9].bodies[M3n[37]]; M3n[1].writeUTF(M3n[4].type); M3n[1].writeUTF(M3n[4].n); M3n[1].writeDouble(M3n[4].p[0]); M3n[1].writeDouble(M3n[4].p[1]); M3n[1].writeDouble(M3n[4].a); M3n[1].writeDouble(M3n[4].fric); M3n[1].writeBoolean(M3n[4].fricp); M3n[1].writeDouble(M3n[4].re); M3n[1].writeDouble(M3n[4].de); M3n[1].writeDouble(M3n[4].lv[0]); M3n[1].writeDouble(M3n[4].lv[1]); M3n[1].writeDouble(M3n[4].av); M3n[1].writeDouble(M3n[4].ld); M3n[1].writeDouble(M3n[4].ad); M3n[1].writeBoolean(M3n[4].fr); M3n[1].writeBoolean(M3n[4].bu); M3n[1].writeDouble(M3n[4].cf.x); M3n[1].writeDouble(M3n[4].cf.y); M3n[1].writeDouble(M3n[4].cf.ct); M3n[1].writeBoolean(M3n[4].cf.w); M3n[1].writeShort(M3n[4].f_c); M3n[1].writeBoolean(M3n[4].f_1); M3n[1].writeBoolean(M3n[4].f_2); M3n[1].writeBoolean(M3n[4].f_3); M3n[1].writeBoolean(M3n[4].f_4); M3n[1].writeBoolean(M3n[4].f_p); M3n[1].writeBoolean(M3n[4].fz.on); if (M3n[4].fz.on) { M3n[1].writeDouble(M3n[4].fz.x); M3n[1].writeDouble(M3n[4].fz.y); M3n[1].writeBoolean(M3n[4].fz.d); M3n[1].writeBoolean(M3n[4].fz.p); M3n[1].writeBoolean(M3n[4].fz.a); M3n[1].writeShort(M3n[4].fz.t); +M3n[1].writeDouble(M3n[4].fz.cf); } M3n[1].writeShort(M3n[4].fx.length); for (M3n[28] = 0; M3n[28] < M3n[4].fx.length; M3n[28]++) { M3n[1].writeShort(M3n[4].fx[M3n[28]]); } } M3n[1].writeShort(M3n[0][0].spawns.length); for (M3n[30] = 0; M3n[30] < M3n[0][0].spawns.length; M3n[30]++) { M3n[6] = M3n[0][0].spawns[M3n[30]]; M3n[1].writeDouble(M3n[6].x); M3n[1].writeDouble(M3n[6].y); M3n[1].writeDouble(M3n[6].xv); M3n[1].writeDouble(M3n[6].yv); M3n[1].writeShort(M3n[6].priority); M3n[1].writeBoolean(M3n[6].r); M3n[1].writeBoolean(M3n[6].f); M3n[1].writeBoolean(M3n[6].b); M3n[1].writeBoolean(M3n[6].gr); M3n[1].writeBoolean(M3n[6].ye); M3n[1].writeUTF(M3n[6].n); } M3n[1].writeShort(M3n[0][0].capZones.length); for (M3n[74] = 0; M3n[74] < M3n[0][0].capZones.length; M3n[74]++) { M3n[3] = M3n[0][0].capZones[M3n[74]]; M3n[1].writeUTF(M3n[3].n); M3n[1].writeDouble(M3n[3].l); M3n[1].writeShort(M3n[3].i); M3n[1].writeShort(M3n[3].ty); } M3n[1].writeShort(M3n[9].joints.length); for (M3n[89] = 0; M3n[89] < M3n[9].joints.length; M3n[89]++) { M3n[5] = M3n[9].joints[M3n[89]]; if (M3n[5].type == "rv") { M3n[1].writeShort(1); M3n[1].writeDouble(M3n[5].d.la); M3n[1].writeDouble(M3n[5].d.ua); M3n[1].writeDouble(M3n[5].d.mmt); M3n[1].writeDouble(M3n[5].d.ms); M3n[1].writeBoolean(M3n[5].d.el); M3n[1].writeBoolean(M3n[5].d.em); M3n[1].writeDouble(M3n[5].aa[0]); M3n[1].writeDouble(M3n[5].aa[1]); } if (M3n[5].type == "d") { M3n[1].writeShort(2); M3n[1].writeDouble(M3n[5].d.fh); M3n[1].writeDouble(M3n[5].d.dr); M3n[1].writeDouble(M3n[5].aa[0]); M3n[1].writeDouble(M3n[5].aa[1]); M3n[1].writeDouble(M3n[5].ab[0]); M3n[1].writeDouble(M3n[5].ab[1]); } if (M3n[5].type == "lpj") { M3n[1].writeShort(3); M3n[1].writeDouble(M3n[5].pax); M3n[1].writeDouble(M3n[5].pay); M3n[1].writeDouble(M3n[5].pa); M3n[1].writeDouble(M3n[5].pf); M3n[1].writeDouble(M3n[5].pl); M3n[1].writeDouble(M3n[5].pu); M3n[1].writeDouble(M3n[5].plen); M3n[1].writeDouble(M3n[5].pms); } if (M3n[5].type == "lsj") { M3n[1].writeShort(4); M3n[1].writeDouble(M3n[5].sax); M3n[1].writeDouble(M3n[5].say); M3n[1].writeDouble(M3n[5].sf); M3n[1].writeDouble(M3n[5].slen); } if (M3n[5].type == "g") { M3n[1].writeShort(5); M3n[1].writeUTF(M3n[5].n); M3n[1].writeShort(M3n[5].ja); M3n[1].writeShort(M3n[5].jb); M3n[1].writeDouble(M3n[5].r); } if (M3n[5].type != "g") { M3n[1].writeShort(M3n[5].ba); M3n[1].writeShort(M3n[5].bb); M3n[1].writeBoolean(M3n[5].d.cc); M3n[1].writeDouble(M3n[5].d.bf); M3n[1].writeBoolean(M3n[5].d.dl); } } M3n[32] = M3n[1].toBase64(); M3n[77] = LZString.compressToEncodedURIComponent(M3n[32]); return M3n[77]; }; bonkAPI.decodeMap = function (map) { var F5W = [arguments]; var b64mapdata = LZString.decompressFromEncodedURIComponent(map); var binaryReader = new bonkAPI_bytebuffer(); binaryReader.fromBase64(b64mapdata, false); map = { v: 1, s: { re: false, nc: false, pq: 1, gd: 25, fl: false }, physics: { shapes: [], fixtures: [], bodies: [], bro: [], joints: [], ppm: 12 }, spawns: [], capZones: [], m: { a: "noauthor", n: "noname", dbv: 2, dbid: -1, authid: -1, date: "", rxid: 0, rxn: "", rxa: "", rxdb: 1, cr: [], pub: false, mo: "", }, }; map.physics = map.physics; map.v = binaryReader.readShort(); if (map.v > 15) { throw new Error("Future map version, please refresh page"); } map.s.re = binaryReader.readBoolean(); map.s.nc = binaryReader.readBoolean(); if (map.v >= 3) { map.s.pq = binaryReader.readShort(); } if (map.v >= 4 && map.v <= 12) { map.s.gd = binaryReader.readShort(); } else if (map.v >= 13) { map.s.gd = binaryReader.readFloat(); } if (map.v >= 9) { map.s.fl = binaryReader.readBoolean(); } map.m.rxn = binaryReader.readUTF(); map.m.rxa = binaryReader.readUTF(); map.m.rxid = binaryReader.readUint(); map.m.rxdb = binaryReader.readShort(); map.m.n = binaryReader.readUTF(); map.m.a = binaryReader.readUTF(); if (map.v >= 10) { map.m.vu = binaryReader.readUint(); map.m.vd = binaryReader.readUint(); } if (map.v >= 4) { F5W[7] = binaryReader.readShort(); for (F5W[83] = 0; F5W[83] < F5W[7]; F5W[83]++) { map.m.cr.push(binaryReader.readUTF()); } } if (map.v >= 5) { map.m.mo = binaryReader.readUTF(); map.m.dbid = binaryReader.readInt(); } if (map.v >= 7) { map.m.pub = binaryReader.readBoolean(); } if (map.v >= 8) { map.m.dbv = binaryReader.readInt(); } map.physics.ppm = binaryReader.readShort(); F5W[4] = binaryReader.readShort(); for (F5W[15] = 0; F5W[15] < F5W[4]; F5W[15]++) { map.physics.bro[F5W[15]] = binaryReader.readShort(); } F5W[6] = binaryReader.readShort(); for (F5W[28] = 0; F5W[28] < F5W[6]; F5W[28]++) { F5W[5] = binaryReader.readShort(); if (F5W[5] == 1) { map.physics.shapes[F5W[28]] = { type: "bx", w: 10, h: 40, c: [0, 0], a: 0.0, sk: false }; map.physics.shapes[F5W[28]].w = binaryReader.readDouble(); map.physics.shapes[F5W[28]].h = binaryReader.readDouble(); map.physics.shapes[F5W[28]].c = [binaryReader.readDouble(), binaryReader.readDouble()]; map.physics.shapes[F5W[28]].a = binaryReader.readDouble(); map.physics.shapes[F5W[28]].sk = binaryReader.readBoolean(); } if (F5W[5] == 2) { map.physics.shapes[F5W[28]] = { type: "ci", r: 25, c: [0, 0], sk: false }; map.physics.shapes[F5W[28]].r = binaryReader.readDouble(); map.physics.shapes[F5W[28]].c = [binaryReader.readDouble(), binaryReader.readDouble()]; map.physics.shapes[F5W[28]].sk = binaryReader.readBoolean(); } if (F5W[5] == 3) { map.physics.shapes[F5W[28]] = { type: "po", v: [], s: 1, a: 0, c: [0, 0] }; map.physics.shapes[F5W[28]].s = binaryReader.readDouble(); map.physics.shapes[F5W[28]].a = binaryReader.readDouble(); map.physics.shapes[F5W[28]].c = [binaryReader.readDouble(), binaryReader.readDouble()]; F5W[74] = binaryReader.readShort(); map.physics.shapes[F5W[28]].v = []; for (F5W[27] = 0; F5W[27] < F5W[74]; F5W[27]++) { map.physics.shapes[F5W[28]].v.push([ binaryReader.readDouble(), binaryReader.readDouble(), ]); } } } F5W[71] = binaryReader.readShort(); for (F5W[17] = 0; F5W[17] < F5W[71]; F5W[17]++) { map.physics.fixtures[F5W[17]] = { sh: 0, n: "Def Fix", fr: 0.3, fp: null, re: 0.8, de: 0.3, f: 0x4f7cac, d: false, np: false, ng: false, }; map.physics.fixtures[F5W[17]].sh = binaryReader.readShort(); map.physics.fixtures[F5W[17]].n = binaryReader.readUTF(); map.physics.fixtures[F5W[17]].fr = binaryReader.readDouble(); if (map.physics.fixtures[F5W[17]].fr == Number.MAX_VALUE) { map.physics.fixtures[F5W[17]].fr = null; } F5W[12] = binaryReader.readShort(); if (F5W[12] == 0) { map.physics.fixtures[F5W[17]].fp = null; } if (F5W[12] == 1) { map.physics.fixtures[F5W[17]].fp = false; } if (F5W[12] == 2) { map.physics.fixtures[F5W[17]].fp = true; } map.physics.fixtures[F5W[17]].re = binaryReader.readDouble(); if (map.physics.fixtures[F5W[17]].re == Number.MAX_VALUE) { map.physics.fixtures[F5W[17]].re = null; } map.physics.fixtures[F5W[17]].de = binaryReader.readDouble(); if (map.physics.fixtures[F5W[17]].de == Number.MAX_VALUE) { map.physics.fixtures[F5W[17]].de = null; } map.physics.fixtures[F5W[17]].f = binaryReader.readUint(); map.physics.fixtures[F5W[17]].d = binaryReader.readBoolean(); map.physics.fixtures[F5W[17]].np = binaryReader.readBoolean(); if (map.v >= 11) { map.physics.fixtures[F5W[17]].ng = binaryReader.readBoolean(); } if (map.v >= 12) { map.physics.fixtures[F5W[17]].ig = binaryReader.readBoolean(); } } F5W[63] = binaryReader.readShort(); for (F5W[52] = 0; F5W[52] < F5W[63]; F5W[52]++) { map.physics.bodies[F5W[52]] = { type: "s", n: "Unnamed", p: [0, 0], a: 0, fric: 0.3, fricp: false, re: 0.8, de: 0.3, lv: [0, 0], av: 0, ld: 0, ad: 0, fr: false, bu: false, cf: { x: 0, y: 0, w: true, ct: 0 }, fx: [], f_c: 1, f_p: true, f_1: true, f_2: true, f_3: true, f_4: true, fz: { on: false, x: 0, y: 0, d: true, p: true, a: true, t: 0, cf: 0 }, }; map.physics.bodies[F5W[52]].type = binaryReader.readUTF(); map.physics.bodies[F5W[52]].n = binaryReader.readUTF(); map.physics.bodies[F5W[52]].p = [binaryReader.readDouble(), binaryReader.readDouble()]; map.physics.bodies[F5W[52]].a = binaryReader.readDouble(); map.physics.bodies[F5W[52]].fric = binaryReader.readDouble(); map.physics.bodies[F5W[52]].fricp = binaryReader.readBoolean(); map.physics.bodies[F5W[52]].re = binaryReader.readDouble(); map.physics.bodies[F5W[52]].de = binaryReader.readDouble(); map.physics.bodies[F5W[52]].lv = [binaryReader.readDouble(), binaryReader.readDouble()]; map.physics.bodies[F5W[52]].av = binaryReader.readDouble(); map.physics.bodies[F5W[52]].ld = binaryReader.readDouble(); map.physics.bodies[F5W[52]].ad = binaryReader.readDouble(); map.physics.bodies[F5W[52]].fr = binaryReader.readBoolean(); map.physics.bodies[F5W[52]].bu = binaryReader.readBoolean(); map.physics.bodies[F5W[52]].cf.x = binaryReader.readDouble(); map.physics.bodies[F5W[52]].cf.y = binaryReader.readDouble(); map.physics.bodies[F5W[52]].cf.ct = binaryReader.readDouble(); map.physics.bodies[F5W[52]].cf.w = binaryReader.readBoolean(); map.physics.bodies[F5W[52]].f_c = binaryReader.readShort(); map.physics.bodies[F5W[52]].f_1 = binaryReader.readBoolean(); map.physics.bodies[F5W[52]].f_2 = binaryReader.readBoolean(); map.physics.bodies[F5W[52]].f_3 = binaryReader.readBoolean(); map.physics.bodies[F5W[52]].f_4 = binaryReader.readBoolean(); if (map.v >= 2) { map.physics.bodies[F5W[52]].f_p = binaryReader.readBoolean(); } if (map.v >= 14) { map.physics.bodies[F5W[52]].fz.on = binaryReader.readBoolean(); if (map.physics.bodies[F5W[52]].fz.on) { map.physics.bodies[F5W[52]].fz.x = binaryReader.readDouble(); map.physics.bodies[F5W[52]].fz.y = binaryReader.readDouble(); map.physics.bodies[F5W[52]].fz.d = binaryReader.readBoolean(); map.physics.bodies[F5W[52]].fz.p = binaryReader.readBoolean(); map.physics.bodies[F5W[52]].fz.a = binaryReader.readBoolean(); if (map.v >= 15) { map.physics.bodies[F5W[52]].t = binaryReader.readShort(); map.physics.bodies[F5W[52]].cf = binaryReader.readDouble(); } } } F5W[88] = binaryReader.readShort(); for (F5W[65] = 0; F5W[65] < F5W[88]; F5W[65]++) { map.physics.bodies[F5W[52]].fx.push(binaryReader.readShort()); } } F5W[97] = binaryReader.readShort(); for (F5W[41] = 0; F5W[41] < F5W[97]; F5W[41]++) { map.spawns[F5W[41]] = { x: 400, y: 300, xv: 0, yv: 0, priority: 5, r: true, f: true, b: true, gr: false, ye: false, n: "Spawn", }; F5W[35] = map.spawns[F5W[41]]; F5W[35].x = binaryReader.readDouble(); F5W[35].y = binaryReader.readDouble(); F5W[35].xv = binaryReader.readDouble(); F5W[35].yv = binaryReader.readDouble(); F5W[35].priority = binaryReader.readShort(); F5W[35].r = binaryReader.readBoolean(); F5W[35].f = binaryReader.readBoolean(); F5W[35].b = binaryReader.readBoolean(); F5W[35].gr = binaryReader.readBoolean(); F5W[35].ye = binaryReader.readBoolean(); F5W[35].n = binaryReader.readUTF(); } F5W[16] = binaryReader.readShort(); for (F5W[25] = 0; F5W[25] < F5W[16]; F5W[25]++) { map.capZones[F5W[25]] = { n: "Cap Zone", ty: 1, l: 10, i: -1 }; map.capZones[F5W[25]].n = binaryReader.readUTF(); map.capZones[F5W[25]].l = binaryReader.readDouble(); map.capZones[F5W[25]].i = binaryReader.readShort(); if (map.v >= 6) { map.capZones[F5W[25]].ty = binaryReader.readShort(); } } F5W[98] = binaryReader.readShort(); for (F5W[19] = 0; F5W[19] < F5W[98]; F5W[19]++) { F5W[31] = binaryReader.readShort(); if (F5W[31] == 1) { map.physics.joints[F5W[19]] = { type: "rv", d: { la: 0, ua: 0, mmt: 0, ms: 0, el: false, em: false, cc: false, bf: 0, dl: true }, aa: [0, 0], }; F5W[20] = map.physics.joints[F5W[19]]; F5W[20].d.la = binaryReader.readDouble(); F5W[20].d.ua = binaryReader.readDouble(); F5W[20].d.mmt = binaryReader.readDouble(); F5W[20].d.ms = binaryReader.readDouble(); F5W[20].d.el = binaryReader.readBoolean(); F5W[20].d.em = binaryReader.readBoolean(); F5W[20].aa = [binaryReader.readDouble(), binaryReader.readDouble()]; } if (F5W[31] == 2) { map.physics.joints[F5W[19]] = { type: "d", d: { fh: 0, dr: 0, cc: false, bf: 0, dl: true }, aa: [0, 0], ab: [0, 0], }; F5W[87] = map.physics.joints[F5W[19]]; F5W[87].d.fh = binaryReader.readDouble(); F5W[87].d.dr = binaryReader.readDouble(); F5W[87].aa = [binaryReader.readDouble(), binaryReader.readDouble()]; F5W[87].ab = [binaryReader.readDouble(), binaryReader.readDouble()]; } if (F5W[31] == 3) { map.physics.joints[F5W[19]] = { type: "lpj", d: { cc: false, bf: 0, dl: true }, pax: 0, pay: 0, pa: 0, pf: 0, pl: 0, pu: 0, plen: 0, pms: 0, }; F5W[90] = map.physics.joints[F5W[19]]; F5W[90].pax = binaryReader.readDouble(); F5W[90].pay = binaryReader.readDouble(); F5W[90].pa = binaryReader.readDouble(); F5W[90].pf = binaryReader.readDouble(); F5W[90].pl = binaryReader.readDouble(); F5W[90].pu = binaryReader.readDouble(); F5W[90].plen = binaryReader.readDouble(); F5W[90].pms = binaryReader.readDouble(); } if (F5W[31] == 4) { map.physics.joints[F5W[19]] = { type: "lsj", d: { cc: false, bf: 0, dl: true }, sax: 0, say: 0, sf: 0, slen: 0, }; F5W[44] = map.physics.joints[F5W[19]]; F5W[44].sax = binaryReader.readDouble(); F5W[44].say = binaryReader.readDouble(); F5W[44].sf = binaryReader.readDouble(); F5W[44].slen = binaryReader.readDouble(); } if (F5W[31] == 5) { map.physics.joints[F5W[19]] = { type: "g", n: "", ja: -1, jb: -1, r: 1 }; F5W[91] = map.physics.joints[F5W[19]]; F5W[91].n = binaryReader.readUTF(); F5W[91].ja = binaryReader.readShort(); F5W[91].jb = binaryReader.readShort(); F5W[91].r = binaryReader.readDouble(); } if (F5W[31] != 5) { map.physics.joints[F5W[19]].ba = binaryReader.readShort(); map.physics.joints[F5W[19]].bb = binaryReader.readShort(); map.physics.joints[F5W[19]].d.cc = binaryReader.readBoolean(); map.physics.joints[F5W[19]].d.bf = binaryReader.readDouble(); map.physics.joints[F5W[19]].d.dl = binaryReader.readBoolean(); } } return map; }; window.PIXI.Graphics.prototype.drawShape = function(...args) { //! testing whether cap can be easily found in drawShape //! in drawCircle, capzone has attribute 'cap: "bet"' inside fill_outline //console.log([...args]); let draw = this; setTimeout(function(){ if(draw.parent) { bonkAPI.parentDraw = draw.parent; while(bonkAPI.parentDraw.parent != null) { bonkAPI.parentDraw = bonkAPI.parentDraw.parent; } } }, 0); return bonkAPI.originalDrawShape.call(this, ...args); } window.requestAnimationFrame = function(...args) { //console.log(bonkAPI.isInGame()); if(bonkAPI.isInGame()) { let canv = 0; for(let i = 0; i < document.getElementById("gamerenderer").children.length; i++) { if(document.getElementById("gamerenderer").children[i].constructor.name == "HTMLCanvasElement"){ canv = document.getElementById("gamerenderer").children[i]; break; } } //console.log(bonkAPI.parentDraw); if(canv != 0 && bonkAPI.parentDraw) { //! might do something might not while(bonkAPI.parentDraw.parent != null) { bonkAPI.parentDraw = bonkAPI.parentDraw.parent; } /** * When a new frame is rendered when in game. It is recomended * to not create new graphics or clear graphics every frame if * possible. * @event graphicsUpdate * @type {object} * @property {string} container - PIXI container to hold PIXI graphics. * @property {number} width - Width of main screen * @property {number} height - Height of main screen */ if(bonkAPI.events.hasEvent["graphicsUpdate"]) { let w = parseInt(canv.style.width); let h = parseInt(canv.style.height); //bonkAPI.pixiCtx.x = w / 2; //bonkAPI.pixiCtx.y = h / 2; bonkAPI.pixiStage = 0; for(let i = 0; i < bonkAPI.parentDraw.children.length; i++){ if(bonkAPI.parentDraw.children[i].constructor.name == "e"){ //console.log(bonkAPI.parentDraw); bonkAPI.pixiStage = bonkAPI.parentDraw.children[i]; break; } } let sendObj = { container: bonkAPI.pixiCtx, width: w, height: h, }; bonkAPI.events.fireEvent("graphicsUpdate", sendObj); if(bonkAPI.pixiStage != 0 && !bonkAPI.pixiStage.children.includes(bonkAPI.pixiCtx)) { bonkAPI.pixiStage.addChild(bonkAPI.pixiCtx); } } } } return bonkAPI.originalRequestAnimationFrame.call(this,...args); } /** * When the map has changed. * @event mapSwitch * @type {object} * @property {PIXI} pixi - PIXI class in order to create graphics and containers. * @property {string} container - PIXI container to hold PIXI graphics. */ if(bonkAPI.events.hasEvent["graphicsReady"]) { let sendObj = { pixi: window.PIXI, container: bonkAPI.pixiCtx, } bonkAPI.events.fireEvent("graphicsReady", sendObj); } bonkHUD.loadStyleSettings(); bonkHUD.initialize(); bonkHUD.updateStyleSettings(); }; bonkLIB.checkDocumentReady = () => { if (document.readyState === "complete" || document.readyState === "interactive") { bonkLIB.onLoaded(); } else { document.addEventListener("DOMContentLoaded", function () { bonkLIB.onLoaded(); }); } }; // Call the function to check document readiness bonkLIB.checkDocumentReady();