Mobile keybinds

- Attack percentage bar is now always redrawn after each keybind use
- UI changes: Slightly decreased the UI font size, adjusted the size of the inputs in the keybind settings and added a small margin under the keybind settings
dev
peshomir 2025-03-02 21:41:05 +02:00
parent 546d17c76b
commit ed94c65172
8 changed files with 140 additions and 10 deletions

View File

@ -56,6 +56,7 @@ script = script.replace(/\bS\[(\d+)\]/g, (_match, index) => `"${stringArray[inde
const modUtils = new ModUtils(minifyCode(script)); const modUtils = new ModUtils(minifyCode(script));
import applyPatches from './patches/main.js'; import applyPatches from './patches/main.js';
console.log("Applying patches...");
applyPatches(modUtils); applyPatches(modUtils);
// for versions ^1.99.5.2 // for versions ^1.99.5.2

View File

@ -0,0 +1,56 @@
export default (/** @type {import('../modUtils.js').default} */ { insertCode, replaceCode, matchCode }) => {
const { mainCanvas, x, y } = insertCode(`this.te = function() {
if (!this.b()) { return; }
mainCanvas.drawImage(canvas, x, this.y);
/* here */
}`, `if (__fx.settings.keybindButtons) __fx.mobileKeybinds.draw(mainCanvas, x, this.y);`)
const { h, redraw } = insertCode(`a6k = Math.floor(3 * this.h / 2);
a4M = c.pZ.rN(1, Math.floor(0.5 * this.h));
canvas = document.createElement("canvas");
canvas.width = w;
/* here */
canvas.height = this.h;
ctx = canvas.getContext("2d", { alpha: true });
ctx.font = a4M;
c.pZ.textBaseline(ctx, 1);
c.pZ.textAlign(ctx, 1);
this.a6m();
redraw();
`, `__fx.mobileKeybinds.setSize(w, this.h, mainCanvas)`, { dictionary: { mainCanvas } })
const { ba, gap } = matchCode(`this.h = Math.floor(0.066 * h___.pb); w = h___.w - 4 * ba.gap - this.h;`);
const { bd, requestRepaint } = insertCode(`this.gm = function(kt, ku) {
if (!this.b()) { return false; }
/* here */
if (!a.a0n(kt, ku)) { return false; }
aR.mC = false;
if (a6w(this, kt, ku)) { bd.requestRepaint = true; }
return true;
};`,
`if (__fx.settings.keybindButtons && ku > this.y - Math.floor(ba.gap / 4) - this.h && ku < this.y - Math.floor(ba.gap / 4) && __fx.mobileKeybinds.click(kt - x)) return true;`,
{ dictionary: { x, y, h, ba, gap } }
)
insertCode(
`var a6l = 11 / 12; /* here */`,
`__fx.keybindFunctions.repaintAttackPercentageBar = function() { redraw(); bd.requestRepaint = true; };`,
{ dictionary: { redraw, bd, requestRepaint } }
)
// fix to correctly display peace vote menu and game messages (prevent overlap with keybind buttons)
replaceCode(`if (a.a4y(aM.a4u())) {
if (au.b) { return a.y - a.h - 2 * a4a; }
else { return a.y - a4a; }
}`, `if (a.a4y(aM.a4u())) {
if (au.b) { return __fx.settings.keybindButtons ? a.y - 2 * a.h - 3 * a4a : a.y - a.h - 2 * a4a; }
else { return __fx.settings.keybindButtons ? a.y - a.h - 2 * a4a : a.y - a4a; }
}`)
insertCode(
`if (a.a4y(aM.a4u())) { return /* here */ a.y - h - ba.gap; }`,
`__fx.settings.keybindButtons ? a.y - 2 * (h + ba.gap) : `
)
}

View File

@ -1,7 +1,10 @@
const playerDataProperties = ["playerTerritories", "playerBalances", "rawPlayerNames"]; const playerDataProperties = ["playerTerritories", "playerBalances", "rawPlayerNames"];
const gameObjectProperties = ["playerId", "gIsTeamGame", "gHumans", "gLobbyMaxJoin", "gameState", "gIsSingleplayer"]; const gameObjectProperties = ["playerId", "gIsTeamGame", "gHumans", "gLobbyMaxJoin", "gameState", "gIsSingleplayer"];
export const getVar = varName => { export const getVar = varName => {
if (playerDataProperties.includes(varName)) return window[dictionary.playerData]?.[dictionary[varName]]; if (playerDataProperties.includes(varName)) return window[dictionary.playerData]?.[dictionary[varName]];
if (gameObjectProperties.includes(varName)) return window[dictionary.game]?.[dictionary[varName]]; if (gameObjectProperties.includes(varName)) return window[dictionary.game]?.[dictionary[varName]];
return window[dictionary[varName]] return window[dictionary[varName]]
}; };
export const getUIGap = () => Math.floor(window[dictionary.uiSizes]?.[dictionary.gap] ?? 10);

View File

@ -1,10 +1,66 @@
import { getUIGap } from "./gameInterface.js";
import { getSettings } from "./settings.js"; import { getSettings } from "./settings.js";
export const keybindFunctions = { setAbsolute: () => {}, setRelative: () => {} }; export const keybindFunctions = {
setAbsolute: () => {},
setRelative: () => {},
repaintAttackPercentageBar: () => {}
};
export const keybindHandler = key => { export const keybindHandler = key => {
const keybindData = getSettings().attackPercentageKeybinds.find(keybind => keybind.key === key); const keybindData = getSettings().attackPercentageKeybinds.find(keybind => keybind.key === key);
if (keybindData === undefined) return false; if (keybindData === undefined) return false;
if (keybindData.type === "absolute") keybindFunctions.setAbsolute(keybindData.value); executeKeybind(keybindData);
else keybindFunctions.setRelative(keybindData.value);
return true; return true;
}; };
function executeKeybind(keybind) {
if (keybind.type === "absolute") keybindFunctions.setAbsolute(keybind.value);
else keybindFunctions.setRelative(keybind.value);
keybindFunctions.repaintAttackPercentageBar();
}
// mobile keybinds (keybind buttons)
let canvas;
let width = 0;
let height = 0;
const maxCount = 6;
export const mobileKeybinds = {
setSize: (w, h, mainCanvas) => {
if (getSettings().keybindButtons !== true) return;
width = w;
height = h;
// redraw
canvas = document.createElement("canvas");
canvas.width = w;
canvas.height = h;
const ctx = canvas.getContext("2d");
const fontName = mainCanvas.font.split("px ", 2)[1];
ctx.font = "bold " + h / 2 + "px " + fontName;
ctx.textAlign = "center";
ctx.textBaseline = "middle";
const keybinds = getSettings().attackPercentageKeybinds.slice(0, maxCount);
const gap = getUIGap() / 4;
const buttonWidth = (w - gap * (maxCount - 1)) / maxCount;
keybinds.forEach((keybind, i) => {
ctx.fillStyle = "rgba(0, 0, 0, 0.8)";
ctx.fillRect(i * (buttonWidth + gap), 0, buttonWidth, h);
ctx.fillStyle = "white";
const label = keybind.type === "absolute" ? (keybind.value * 100).toFixed() + "%" : "x " + Math.round(keybind.value * 100) / 100;
ctx.fillText(label, (i + 0.5) * (buttonWidth + gap), h / 2);
});
},
click: (xRelative) => {
if (xRelative < 0 || xRelative > width) return false;
const keybinds = getSettings().attackPercentageKeybinds;
const index = Math.floor(xRelative / width * maxCount);
if (index >= keybinds.length) return false;
executeKeybind(keybinds[index]);
return true;
},
draw: (mainCanvas, x, y) => {
mainCanvas.drawImage(canvas, x, y - (height + getUIGap() / 4));
}
}

View File

@ -1,4 +1,4 @@
export function KeybindsInput(containerElement) { export function KeybindsInput(/** @type {HTMLElement} */ containerElement) {
const header = document.createElement("p"); const header = document.createElement("p");
header.innerText = "Attack Percentage Keybinds"; header.innerText = "Attack Percentage Keybinds";
const keybindContainer = document.createElement("div"); const keybindContainer = document.createElement("div");
@ -6,6 +6,7 @@ export function KeybindsInput(containerElement) {
const keybindAddButton = document.createElement("button"); const keybindAddButton = document.createElement("button");
keybindAddButton.innerText = "Add"; keybindAddButton.innerText = "Add";
containerElement.append(header, keybindContainer, keybindAddButton); containerElement.append(header, keybindContainer, keybindAddButton);
containerElement.className = "keybinds-input";
this.container = keybindContainer; this.container = keybindContainer;
this.keys = [ "key", "type", "value" ]; this.keys = [ "key", "type", "value" ];
this.objectArray = []; this.objectArray = [];

View File

@ -1,5 +1,5 @@
const fx_version = '0.6.7.1'; // FX Client Version const fx_version = '0.6.7.2'; // FX Client Version
const fx_update = 'Feb 15'; // FX Client Last Updated const fx_update = 'Mar 2'; // FX Client Last Updated
if ("serviceWorker" in navigator) { if ("serviceWorker" in navigator) {
navigator.serviceWorker.addEventListener("message", (e) => { navigator.serviceWorker.addEventListener("message", (e) => {
@ -20,7 +20,7 @@ import winCounter from "./winCounter.js";
import playerList from "./playerList.js"; import playerList from "./playerList.js";
import gameScriptUtils from "./gameScriptUtils.js"; import gameScriptUtils from "./gameScriptUtils.js";
import hoveringTooltip from "./hoveringTooltip.js"; import hoveringTooltip from "./hoveringTooltip.js";
import { keybindFunctions, keybindHandler } from "./keybinds.js"; import { keybindFunctions, keybindHandler, mobileKeybinds } from "./keybinds.js";
import customLobby from './customLobby.js'; import customLobby from './customLobby.js';
window.__fx = window.__fx || {}; window.__fx = window.__fx || {};
@ -33,6 +33,7 @@ __fx.utils = gameScriptUtils;
__fx.WindowManager = WindowManager; __fx.WindowManager = WindowManager;
__fx.keybindFunctions = keybindFunctions; __fx.keybindFunctions = keybindFunctions;
__fx.keybindHandler = keybindHandler; __fx.keybindHandler = keybindHandler;
__fx.mobileKeybinds = mobileKeybinds;
__fx.donationsTracker = donationsTracker; __fx.donationsTracker = donationsTracker;
__fx.playerList = playerList; __fx.playerList = playerList;
__fx.hoveringTooltip = hoveringTooltip; __fx.hoveringTooltip = hoveringTooltip;

View File

@ -21,6 +21,7 @@ var settings = {
detailedTeamPercentage: false, detailedTeamPercentage: false,
//"customMapFileBtn": true //"customMapFileBtn": true
customBackgroundUrl: "", customBackgroundUrl: "",
keybindButtons: false,
attackPercentageKeybinds: [], attackPercentageKeybinds: [],
}; };
__fx.settings = settings; __fx.settings = settings;
@ -102,6 +103,10 @@ const settingsManager = new (function () {
"A custom image to be shown as the main menu background instead of the currently selected map.", "A custom image to be shown as the main menu background instead of the currently selected map.",
}, },
KeybindsInput, KeybindsInput,
{
for: "keybindButtons", type: "checkbox",
label: "Keybind buttons", note: "Show keybind buttons above the troop selector (max 6)"
}
]; ];
const settingsContainer = document.querySelector(".settings .scrollable"); const settingsContainer = document.querySelector(".settings .scrollable");
var inputFields = {}; // (includes select menus) var inputFields = {}; // (includes select menus)

View File

@ -28,7 +28,7 @@
border-width : 2px; border-width : 2px;
border-width : calc(0.15 * (1vw + 1vh)); border-width : calc(0.15 * (1vw + 1vh));
font-size : 20px; font-size : 20px;
font-size : calc(14px + ((0.5 * (1.1vw - 0.1vh)) + 0.14rem)); font-size : calc(13px + ((0.5 * (1.1vw - 0.1vh)) + 0.14rem));
max-height : 90%; max-height : 90%;
transition : 0.2s; transition : 0.2s;
z-index : 10; z-index : 10;
@ -59,6 +59,13 @@
margin: 0px; margin: 0px;
} }
.keybinds-input {
margin-bottom: 1em;
}
.keybinds-input input {
width: 10em;
}
.flex { .flex {
display: flex; display: flex;
} }