From 5fdf36ddad7f615696bce3ca88d148dac8373148 Mon Sep 17 00:00:00 2001 From: peshomir <80340328+peshomir@users.noreply.github.com> Date: Wed, 21 Feb 2024 21:58:22 +0200 Subject: [PATCH] Update v0.6.1; Add keybinds --- build.js | 22 +++++++++++++ static/fx_core.js | 83 +++++++++++++++++++++++++++++++++++++++++++++-- static/index.html | 3 ++ static/main.css | 3 +- 4 files changed, 108 insertions(+), 3 deletions(-) diff --git a/build.js b/build.js index 78c7ca1..cfd972d 100644 --- a/build.js +++ b/build.js @@ -13,6 +13,14 @@ const replaceOne = (expression, replaceValue) => { script = script.replace(expression, replaceValue); return result; } +const matchOne = (expression) => { + const result = expression.exec(script); + if (result === null) throw new Error("no match for: ") + expression; + if (expression.exec(script) !== null) throw new Error("more than one match for: " + expression); + return result; +} +// https://stackoverflow.com/a/63838890 +const escapeRegExp = (string) => string.replace(/[.*+\-?^${}()|[\]\\]/g, '\\$&'); //const dictionary = { __dictionaryVersion: '1.90.0 4 Feb 2024', playerId: 'bB', playerNames: 'hA', playerBalances: 'bC', playerTerritories: 'bj', gIsSingleplayer: 'fc', gIsTeamGame: 'cH' }; //if (!script.includes(`"${dictionary.__dictionaryVersion}"`)) throw new Error("Dictionary is outdated."); @@ -89,6 +97,20 @@ replaceOne(/(this\.\w+=function\((?\w+),(?\w+)\){[^}]+?)if\((?) $'); } +{ // Keybinds + // match required variables + const { 0: match, groups: { attackBarObject, setRelative } } = matchOne(/:"."===(\w+\.key)\?(?\w+)\.(?\w+)\(31\/32\):"."===\1\?\2\.\3\(32\/31\):/g,); + // create a setAbsolutePercentage function on the attack percentage bar object, + // and also register the keybind handler functions + replaceOne(/}(function \w+\((\w+)\){return!\(1<\2&&1===(?\w+)\|\|\(1<\2&&\2\*\3-\3<1\/1024\?\2=\(\3\+1\/1024\)\/\3:\2<1)/g, + "} this.setAbsolutePercentage = function(newPercentage) { $ = newPercentage; }; " + + "keybindFunctions.setAbsolute = this.setAbsolutePercentage; " + + `keybindFunctions.setRelative = (arg1) => ${attackBarObject}.${setRelative}(arg1); $1`); + // insert keybind handling code into the keyDown handler function + replaceOne(new RegExp(/(function \w+\((?\w+)\){)([^}]+matched)/g.source.replace(/matched/g, escapeRegExp(match)), "g"), + "$1 if (keybindHandler($.key)) return; $3"); +} + // Enforce custom font name script = script.replace(/"px sans-serif"/g, '"px " + settings.fontName'); diff --git a/static/fx_core.js b/static/fx_core.js index 0e488cf..c67afcc 100644 --- a/static/fx_core.js +++ b/static/fx_core.js @@ -1,5 +1,5 @@ -const fx_version = '0.6.0.3'; // FX Client Version -const fx_update = 'Feb 15'; // FX Client Last Updated +const fx_version = '0.6.1'; // FX Client Version +const fx_update = 'Feb 21'; // FX Client Last Updated if (localStorage.getItem("fx_winCount") == undefined || localStorage.getItem("fx_winCount") == null) { @@ -9,12 +9,79 @@ if (localStorage.getItem("fx_winCount") == undefined || localStorage.getItem("fx var wins_counter = localStorage.getItem("fx_winCount"); } +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 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) { + if (key === "type") { + var selectMenu = document.createElement("select"); + selectMenu.innerHTML = ''; + selectMenu.value = this.objectArray[i][key]; + selectMenu.addEventListener("change", this.updateObject.bind(this, i, key)); + objectDiv.appendChild(selectMenu); + return; + } + var inputField = document.createElement("input"); + inputField.type = key === "value" ? "number" : "text"; + if (key === "value") inputField.setAttribute("step", "0.1"); + if (key === "key") inputField.setAttribute("readonly", ""); + inputField.value = this.objectArray[i][key]; + if (key === "key") inputField.addEventListener("click", this.startKeyInput.bind(this, i, key)); + else inputField.addEventListener("input", this.updateObject.bind(this, 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); + } + }; + this.startKeyInput = function (index, property, event) { + event.target.value = "Press any key"; + document.addEventListener('keydown', this.updateObject.bind(this, index, property), { 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, "hideAllLinks": false, "realisticNames": false, //"customMapFileBtn": true + "attackPercentageKeybinds": [], }; var settingsManager = new (function() { var inputFields = { @@ -35,9 +102,12 @@ var settingsManager = new (function() { // 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; @@ -138,6 +208,15 @@ var utils = new (function() { }; }); +const keybindFunctions = { setAbsolute: () => {}, setRelative: () => {} }; +const keybindHandler = key => { + const keybindData = settings.attackPercentageKeybinds.find(keybind => keybind.key === key); + if (keybindData === undefined) return false; + if (keybindData.type === "absolute") keybindFunctions.setAbsolute(keybindData.value); + else keybindFunctions.setRelative(keybindData.value); + return true; +}; + if (localStorage.getItem("fx_settings") !== null) { settings = {...settings, ...JSON.parse(localStorage.getItem("fx_settings"))}; } diff --git a/static/index.html b/static/index.html index bfb8b40..1d82e5c 100644 --- a/static/index.html +++ b/static/index.html @@ -76,6 +76,9 @@ Bring back the custom map file button after the creator removed it in 1.83.0 --> +

Keybinds

+
+