const fx_version = '0.6.2.1'; // FX Client Version const fx_update = 'Mar 10'; // FX Client Last Updated if (localStorage.getItem("fx_winCount") == undefined || localStorage.getItem("fx_winCount") == null) { var wins_counter = 0; console.log('Couldn\'t find a saved win data. creating one...'); } else if (localStorage.getItem("fx_winCount") != undefined || localStorage.getItem("fx_winCount") != null) { var wins_counter = localStorage.getItem("fx_winCount"); } const getVar = varName => window[dictionary[varName]]; // https://stackoverflow.com/a/6234804 function escapeHtml(unsafe) { return unsafe.replace(/&/g, "&").replace(//g, ">").replace(/"/g, """).replace(/'/g, "'"); } function KeybindsInput(containerElement) { this.container = containerElement; this.keys = [ "key", "type", "value" ]; this.objectArray = []; this.addObject = function () { this.objectArray.push({ key: "", type: "absolute", value: 1 }); this.displayObjects(); }; document.getElementById("keybindAddButton").addEventListener("click", this.addObject.bind(this)); this.displayObjects = function () { // Clear the content of the container this.container.innerHTML = ""; if (this.objectArray.length === 0) return this.container.innerText = "No custom attack percentage keybinds added"; // Loop through the array and display input fields for each object for (var i = 0; i < this.objectArray.length; i++) { var objectDiv = document.createElement("div"); // Create input fields for each key this.keys.forEach(function (key) { let inputField = document.createElement(key === "type" ? "select" : "input"); if (key === "type") { inputField.innerHTML = ''; inputField.addEventListener("change", this.updateObject.bind(this, i, key)); } else if (key === "key") { inputField.type = "text"; inputField.setAttribute("readonly", ""); inputField.setAttribute("placeholder", "No key set"); inputField.addEventListener("click", this.startKeyInput.bind(this, i, key)); } else { // key === "value" inputField.type = "number"; inputField.setAttribute("step", "0.1"); inputField.addEventListener("input", this.updateObject.bind(this, i, key)); } inputField.value = this.objectArray[i][key]; // Append input field to the object div objectDiv.appendChild(inputField); }, this); // Button to delete the object var deleteButton = document.createElement("button"); deleteButton.textContent = "Delete"; deleteButton.addEventListener("click", this.deleteObject.bind(this, i)); // Append delete button to the object div objectDiv.appendChild(deleteButton); // Append the object div to the container this.container.appendChild(objectDiv); } }; /** @param {PointerEvent} event */ this.startKeyInput = function (index, property, event) { event.target.value = "Press any key"; const handler = this.updateObject.bind(this, index, property); event.target.addEventListener('keydown', handler, { once: true }); event.target.addEventListener("blur", () => { event.target.removeEventListener('keydown', handler, { once: true }); event.target.value = this.objectArray[index][property]; //this.displayObjects(); }, { once: true }); }; this.updateObject = function (index, property, event) { if (index >= this.objectArray.length) return; // Update the corresponding property of the object in the array const value = property === "value" ? parseFloat(event.target.value) : property === "key" ? event.key : event.target.value; this.objectArray[index][property] = value; if (property === "key") this.displayObjects(); }; this.deleteObject = function (index) { // Remove the object from the array this.objectArray.splice(index, 1); // Display the updated input fields for objects this.displayObjects(); }; return this; } var settings = { "fontName": "Trebuchet MS", "showBotDonations": false, "displayWinCounter": true, "useFullscreenMode": false, "hideAllLinks": false, "realisticNames": false, "showPlayerDensity": true, "densityDisplayStyle": "percentage", //"customMapFileBtn": true "customBackgroundUrl": "", "attackPercentageKeybinds": [], }; let makeMainMenuTransparent = false; var settingsManager = new (function() { var inputFields = { // (includes select menus) fontName: document.getElementById("settings_fontname"), customBackgroundUrl: document.getElementById("settings_custombackgroundurl"), densityDisplayStyle: document.getElementById("settings_densityDisplayStyle") }; var checkboxFields = { //showBotDonations: document.getElementById("settings_donations_bots"), hideAllLinks: document.getElementById("settings_hidealllinks"), realisticNames: document.getElementById("settings_realisticnames"), displayWinCounter: document.getElementById("settings_displaywincounter"), useFullscreenMode: document.getElementById("settings_usefullscreenmode"), showPlayerDensity: document.getElementById("settings_showPlayerDensity"), //customMapFileBtn: document.getElementById("settings_custommapfileinput") }; this.save = function() { Object.keys(inputFields).forEach(function(key) { settings[key] = inputFields[key].value.trim(); }); Object.keys(checkboxFields).forEach(function(key) { settings[key] = checkboxFields[key].checked; }); this.applySettings(); WindowManager.closeWindow("settings"); localStorage.setItem("fx_settings", JSON.stringify(settings)); // should probably firgure out a way to do this without reloading - // You can't do it, localstorages REQUIRE you to reload window.location.reload(); }; let keybindsInput = new KeybindsInput(document.getElementById("keybinds")); this.syncFields = function() { Object.keys(inputFields).forEach(function(key) { inputFields[key].value = settings[key]; }); Object.keys(checkboxFields).forEach(function(key) { checkboxFields[key].checked = settings[key]; }); keybindsInput.objectArray = settings.attackPercentageKeybinds; keybindsInput.displayObjects(); }; this.resetAll = function() { if (!confirm("Are you Really SURE you want to RESET ALL SETTINGS back to the default?")) return; localStorage.removeItem("fx_settings"); window.location.reload(); }; this.applySettings = function() { //setVarByName("bu", "px " + settings.fontName); if (settings.useFullscreenMode && document.fullscreenEnabled) { function tryEnterFullscreen() { if (document.fullscreenElement !== null) return; document.documentElement.requestFullscreen({ navigationUI: "hide" }) .then(() => { console.log('Fullscreen mode activated'); }) .catch((error) => { console.warn('Could not enter fullscreen mode:', error); }); } document.addEventListener('mousedown', tryEnterFullscreen, { once: true }); document.addEventListener('click', tryEnterFullscreen, { once: true }); } if (settings.customBackgroundUrl !== "") { document.body.style.backgroundImage = "url(" + settings.customBackgroundUrl + ")"; document.body.style.backgroundSize = "cover"; document.body.style.backgroundPosition = "center"; } makeMainMenuTransparent = settings.customBackgroundUrl !== ""; }; }); function removeWins() { var confirm1 = confirm('Do you really want to reset your Wins?'); if (confirm1) { wins_counter = 0; localStorage.removeItem('fx_winCount'); alert("Successfully reset wins"); } } const openCustomBackgroundFilePicker = () => { const fileInput = document.getElementById("customBackgroundFileInput"); fileInput.click(); fileInput.addEventListener('change', handleFileSelect); } function handleFileSelect(event) { const fileInput = event.target; const selectedFile = fileInput.files[0]; console.log(fileInput.files); console.log(fileInput.files[0]); if (selectedFile) { const fileUrl = URL.createObjectURL(selectedFile); console.log("File URL:", fileUrl); fileInput.value = ""; fileInput.removeEventListener("change", handleFileSelect); } } var WindowManager = new (function() { var windows = {}; this.add = function(newWindow) { windows[newWindow.name] = newWindow; windows[newWindow.name].isOpen = false; }; this.openWindow = function(windowName, ...args) { if (windows[windowName].isOpen === true) return; if (windows[windowName].beforeOpen !== undefined) windows[windowName].beforeOpen(...args); windows[windowName].isOpen = true; windows[windowName].element.style.display = null; }; this.closeWindow = function(windowName) { if (windows[windowName].isOpen === false) return; windows[windowName].isOpen = false; windows[windowName].element.style.display = "none"; if (windows[windowName].onClose !== undefined) windows[windowName].onClose(); }; this.closeAll = function() { Object.values(windows).forEach(function(windowObj) { WindowManager.closeWindow(windowObj.name); }); }; }); WindowManager.add({ name: "settings", element: document.querySelector(".settings"), beforeOpen: function() { settingsManager.syncFields(); } }); WindowManager.add({ name: "donationHistory", element: document.querySelector("#donationhistory"), beforeOpen: function(isSingleplayer) { document.getElementById("donationhistory_note").style.display = ((true || settings.showBotDonations || /*getVarByName("dt")*/ isSingleplayer) ? "none" : "block"); }, onClose: function() { donationsTracker.openedWindowPlayerID = null; } }); WindowManager.add({ name: "playerList", element: document.getElementById("playerlist"), beforeOpen: function() {} }); document.getElementById("canvasA").addEventListener("mousedown", WindowManager.closeAll); document.getElementById("canvasA").addEventListener("touchstart", WindowManager.closeAll, { passive: true }); document.addEventListener("keydown", event => { if (event.key === "Escape") WindowManager.closeAll(); }); var settingsGearIcon = document.createElement('img'); settingsGearIcon.setAttribute('src', 'assets/geari_white.png'); const playerList = new (function () { const playersIcon = document.createElement('img'); playersIcon.setAttribute('src', 'assets/players_icon.png'); document.getElementById("playerlist_content").addEventListener("click", event => { const playerId = event.target.closest("tr[data-player-id]")?.getAttribute("data-player-id"); if (!playerId) return; if (getVar("gIsTeamGame")) WindowManager.closeWindow("playerList"), donationsTracker.displayHistory(playerId); }); this.display = function displayPlayerList(playerNames) { const gHumans = getVar("gHumans"); const gLobbyMaxJoin = getVar("gLobbyMaxJoin"); let listContent = `