Compare commits
	
		
			No commits in common. "ed94c651729b3b525a3390bfcfa4e1bf63c230a0" and "eb216fd0e4fab37b8a9a95c4eeab86c36297337f" have entirely different histories. 
		
	
	
		
			ed94c65172
			...
			eb216fd0e4
		
	
		
	
								
									
									
										
											1
										
									
									build.js
									
									
									
									
								
								
							
							
										
											1
										
									
									build.js
									
									
									
									
								| 
						 | 
					@ -56,7 +56,6 @@ 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
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
								
									
									
										
											52
										
									
									modUtils.js
									
									
									
									
								
								
							
							
										
											52
										
									
									modUtils.js
									
									
									
									
								| 
						 | 
					@ -5,8 +5,6 @@ import UglifyJS from 'uglify-js';
 | 
				
			||||||
const escapeRegExp = (/** @type {string} */ string) => string.replace(/[.*+\-?^${}()|[\]\\]/g, '\\$&');
 | 
					const escapeRegExp = (/** @type {string} */ string) => string.replace(/[.*+\-?^${}()|[\]\\]/g, '\\$&');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function minifyCode(/** @type {string} */ script) {
 | 
					export function minifyCode(/** @type {string} */ script) {
 | 
				
			||||||
    // "return" statements outside of a function throw a parse error
 | 
					 | 
				
			||||||
    script = "()=>{" + script + "}";
 | 
					 | 
				
			||||||
    const output = UglifyJS.minify(script, {
 | 
					    const output = UglifyJS.minify(script, {
 | 
				
			||||||
        compress: false,
 | 
					        compress: false,
 | 
				
			||||||
        mangle: false
 | 
					        mangle: false
 | 
				
			||||||
| 
						 | 
					@ -14,10 +12,7 @@ export function minifyCode(/** @type {string} */ script) {
 | 
				
			||||||
    if (output.error) throw output.error;
 | 
					    if (output.error) throw output.error;
 | 
				
			||||||
    if (output.warnings) throw (output.warnings);
 | 
					    if (output.warnings) throw (output.warnings);
 | 
				
			||||||
    if (output.warnings) console.warn(output.warnings);
 | 
					    if (output.warnings) console.warn(output.warnings);
 | 
				
			||||||
    let code = output.code;
 | 
					    return output.code;
 | 
				
			||||||
    if (code.endsWith(";")) code = code.slice(0, -1);
 | 
					 | 
				
			||||||
    code = code.slice(5, -1); // unwrap from function
 | 
					 | 
				
			||||||
    return code;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ModUtils {
 | 
					class ModUtils {
 | 
				
			||||||
| 
						 | 
					@ -39,8 +34,6 @@ class ModUtils {
 | 
				
			||||||
        this.matchRawCode = this.matchRawCode.bind(this);
 | 
					        this.matchRawCode = this.matchRawCode.bind(this);
 | 
				
			||||||
        this.replaceCode = this.replaceCode.bind(this);
 | 
					        this.replaceCode = this.replaceCode.bind(this);
 | 
				
			||||||
        this.waitForMinification = this.waitForMinification.bind(this);
 | 
					        this.waitForMinification = this.waitForMinification.bind(this);
 | 
				
			||||||
        this.matchCode = this.matchCode.bind(this);
 | 
					 | 
				
			||||||
        this.insertCode = this.insertCode.bind(this);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    /** @param {RegExp} expression */
 | 
					    /** @param {RegExp} expression */
 | 
				
			||||||
| 
						 | 
					@ -78,13 +71,11 @@ class ModUtils {
 | 
				
			||||||
    // Return value example:
 | 
					    // Return value example:
 | 
				
			||||||
    // When replaceRawCode or matchRawCode are called with "var1=var2+1;" as the code
 | 
					    // When replaceRawCode or matchRawCode are called with "var1=var2+1;" as the code
 | 
				
			||||||
    // and this matches "a=b+1;", the returned value will be the object: { var1: "a", var2: "b" }
 | 
					    // and this matches "a=b+1;", the returned value will be the object: { var1: "a", var2: "b" }
 | 
				
			||||||
    /** @param {{ [x: string]: string; }} [nameMappings] */
 | 
					 | 
				
			||||||
    replaceRawCode(/** @type {string} */ raw, /** @type {string} */ result, nameMappings) {
 | 
					    replaceRawCode(/** @type {string} */ raw, /** @type {string} */ result, nameMappings) {
 | 
				
			||||||
        const { expression, groups } = this.generateRegularExpression(raw, false, nameMappings);
 | 
					        const { expression, groups } = this.generateRegularExpression(raw, false, nameMappings);
 | 
				
			||||||
        let localizerCount = 0;
 | 
					        let localizerCount = 0;
 | 
				
			||||||
        let replacementString = result.replaceAll("$", "$$").replaceAll("__L()", "__L)").replaceAll("__L(", "__L,")
 | 
					        let replacementString = result.replaceAll("$", "$$").replaceAll("__L()", "__L)").replaceAll("__L(", "__L,")
 | 
				
			||||||
            .replace(/\w+/g, match => {
 | 
					            .replace(/\w+/g, match => {
 | 
				
			||||||
                if (nameMappings !== undefined && nameMappings.hasOwnProperty(match)) return nameMappings[match];
 | 
					 | 
				
			||||||
                // these would get stored as "___localizer1", "___localizer2", ...
 | 
					                // these would get stored as "___localizer1", "___localizer2", ...
 | 
				
			||||||
                if (match === "__L") match = "___localizer" + (++localizerCount);
 | 
					                if (match === "__L") match = "___localizer" + (++localizerCount);
 | 
				
			||||||
                return groups.hasOwnProperty(match) ? "$" + groups[match] : match;
 | 
					                return groups.hasOwnProperty(match) ? "$" + groups[match] : match;
 | 
				
			||||||
| 
						 | 
					@ -99,14 +90,8 @@ class ModUtils {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    matchRawCode(/** @type {string} */ raw, nameMappings) {
 | 
					    matchRawCode(/** @type {string} */ raw, nameMappings) {
 | 
				
			||||||
        const { expression, groups } = this.generateRegularExpression(raw, false, nameMappings);
 | 
					        const { expression, groups } = this.generateRegularExpression(raw, false, nameMappings);
 | 
				
			||||||
        try {
 | 
					 | 
				
			||||||
        const expressionMatchResult = this.matchOne(expression);
 | 
					        const expressionMatchResult = this.matchOne(expression);
 | 
				
			||||||
            return Object.fromEntries(Object.entries(groups).map(
 | 
					        return Object.fromEntries(Object.entries(groups).map(([identifier, groupNumber]) => [identifier, expressionMatchResult[groupNumber]]));
 | 
				
			||||||
                ([identifier, groupNumber]) => [identifier, expressionMatchResult[groupNumber]]
 | 
					 | 
				
			||||||
            ));
 | 
					 | 
				
			||||||
        } catch (e) {
 | 
					 | 
				
			||||||
            throw new Error("matchRawCode match error:\n\n" + e + "\n\nRaw code: " + raw + "\n");
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    generateRegularExpression(/** @type {string} */ code, /** @type {boolean} */ isForDictionary, nameMappings) {
 | 
					    generateRegularExpression(/** @type {string} */ code, /** @type {boolean} */ isForDictionary, nameMappings) {
 | 
				
			||||||
        const groups = {};
 | 
					        const groups = {};
 | 
				
			||||||
| 
						 | 
					@ -134,38 +119,9 @@ class ModUtils {
 | 
				
			||||||
        let expression = new RegExp(isForDictionary ? raw.replaceAll("@@", "@") : raw, "g");
 | 
					        let expression = new RegExp(isForDictionary ? raw.replaceAll("@@", "@") : raw, "g");
 | 
				
			||||||
        return { expression, groups };
 | 
					        return { expression, groups };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    replaceCode(code, replacement, options) {
 | 
				
			||||||
    /**
 | 
					        return this.replaceRawCode(minifyCode(code), replacement);
 | 
				
			||||||
     * @typedef {{ dictionary?: { [x: string]: string } }} BaseOptions
 | 
					 | 
				
			||||||
     * @typedef {BaseOptions & { addToDictionary?: string[] }} MatchCodeOptions
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    matchCode(code, /** @type {MatchCodeOptions=} */ options) {
 | 
					 | 
				
			||||||
        const result = this.matchRawCode(minifyCode(code));
 | 
					 | 
				
			||||||
        if (options?.addToDictionary !== undefined) {
 | 
					 | 
				
			||||||
            options.addToDictionary.forEach(varName => {
 | 
					 | 
				
			||||||
                if (result[varName] === undefined)
 | 
					 | 
				
			||||||
                    throw new Error(`matchCode addToDictionary error: ${varName} was undefined in the match results`)
 | 
					 | 
				
			||||||
                this.addToDictionary(varName, result[varName]);
 | 
					 | 
				
			||||||
            });
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
        return result;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    replaceCode(/** @type {string} */ code, /** @type {string} */ replacement, /** @type {BaseOptions=} */ options) {
 | 
					 | 
				
			||||||
        return this.replaceRawCode(minifyCode(code), replacement, options?.dictionary);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * @param {string} code
 | 
					 | 
				
			||||||
     * @param {string} codeToInsert
 | 
					 | 
				
			||||||
     * @param {BaseOptions} [options]
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    insertCode(code, codeToInsert, options) {
 | 
					 | 
				
			||||||
        const insertionPoint = "/* here */";
 | 
					 | 
				
			||||||
        if (!code.includes(insertionPoint)) throw new Error("insertCode: No insertion point found");
 | 
					 | 
				
			||||||
        return this.replaceCode(code.replace(insertionPoint, ""), code.replace(insertionPoint, codeToInsert), options);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    waitForMinification(/** @type {Function} */ handler) {
 | 
					    waitForMinification(/** @type {Function} */ handler) {
 | 
				
			||||||
        this.postMinifyHandlers.push(handler);
 | 
					        this.postMinifyHandlers.push(handler);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,17 +1,23 @@
 | 
				
			||||||
import ModUtils from '../modUtils.js';
 | 
					import ModUtils from '../modUtils.js';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Custom lobby patches
 | 
					// Custom lobby patches
 | 
				
			||||||
export default (/** @type {ModUtils} */ { insertCode, replaceRawCode, dictionary: dict, waitForMinification }) => {
 | 
					export default (/** @type {ModUtils} */ { replaceCode, replaceRawCode, dictionary: dict, waitForMinification }) => {
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    // set player id correctly
 | 
					    // set player id correctly
 | 
				
			||||||
    insertCode(`function aBG(aBE) {
 | 
					    replaceCode(`function aBG(aBE) {
 | 
				
			||||||
		if (!Lobby.aAl) { return -1; }
 | 
							if (!Lobby.aAl) { return -1; }
 | 
				
			||||||
        /* here */
 | 
					 | 
				
			||||||
		var s = aBE.length;
 | 
							var s = aBE.length;
 | 
				
			||||||
		var qu = Lobby.aAl.qu;
 | 
							var qu = Lobby.aAl.qu;
 | 
				
			||||||
		for (var i = 0; i < s; i++) { if (aBE[i].qu === qu) { return i; } }
 | 
							for (var i = 0; i < s; i++) { if (aBE[i].qu === qu) { return i; } }
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}`, `if (__fx.customLobby.isActive()) return __fx.customLobby.getPlayerId();`);
 | 
						}`, `function aBG(aBE) {
 | 
				
			||||||
 | 
							if (!Lobby.aAl) { return -1; }
 | 
				
			||||||
 | 
					        if (__fx.customLobby.isActive()) return __fx.customLobby.getPlayerId();
 | 
				
			||||||
 | 
							var s = aBE.length;
 | 
				
			||||||
 | 
							var qu = Lobby.aAl.qu;
 | 
				
			||||||
 | 
							for (var i = 0; i < s; i++) { if (aBE[i].qu === qu) { return i; } }
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}`);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    waitForMinification(() => {
 | 
					    waitForMinification(() => {
 | 
				
			||||||
        replaceRawCode("this.aHm=function(){i___.rX(),aM.a7U(0),aM.init()}",
 | 
					        replaceRawCode("this.aHm=function(){i___.rX(),aM.a7U(0),aM.init()}",
 | 
				
			||||||
| 
						 | 
					@ -36,10 +42,10 @@ export default (/** @type {ModUtils} */ { insertCode, replaceRawCode, dictionary
 | 
				
			||||||
            wR===1 && __fx.customLobby.isActive() && ${dict.MenuManager}.${dict.getState}() !== 6 && __fx.customLobby.setActive(false);
 | 
					            wR===1 && __fx.customLobby.isActive() && ${dict.MenuManager}.${dict.getState}() !== 6 && __fx.customLobby.setActive(false);
 | 
				
			||||||
            if(8===i.pz&&0===wR)if(4211===d)wS(d);`)
 | 
					            if(8===i.pz&&0===wR)if(4211===d)wS(d);`)
 | 
				
			||||||
        // when leaving a game
 | 
					        // when leaving a game
 | 
				
			||||||
        replaceRawCode("this.wl=function(zs){a1.gZ||az.oO.a11.length||(az.oO.a11=az.a12.vd()),ap.ky.zt(),this.vH=0,bU.zu(),m.n.setState(0),aN.setState(0),zs||bJ.df.show(),2===this.a3D?i.ky.a3U():1===this.a3D?i.j(19):i.j(5,5)}",
 | 
					        replaceRawCode("this.wl=function(zs){a1.gZ||az.oO.a11.length||(az.oO.a11=az.a12.vd()),ap.ky.zt(),this.vH=0,bU.zu(),m.n.setState(0),zs||bJ.df.show(),aN.setState(0),2===this.a3D?i.ky.a3U():1===this.a3D?i.j(19):i.j(5,5)}",
 | 
				
			||||||
            `this.wl=function(zs){a1.gZ||az.oO.a11.length||(az.oO.a11=az.a12.vd()),
 | 
					            `this.wl=function(zs){a1.gZ||az.oO.a11.length||(az.oO.a11=az.a12.vd()),
 | 
				
			||||||
            __fx.customLobby.isActive() === false && ap.ky.zt(),
 | 
					            __fx.customLobby.isActive() === false && ap.ky.zt(),
 | 
				
			||||||
            this.vH=0,bU.zu(),m.n.setState(0),aN.setState(0),zs||bJ.df.show();
 | 
					            this.vH=0,bU.zu(),m.n.setState(0),zs||bJ.df.show(),aN.setState(0);
 | 
				
			||||||
            if (__fx.customLobby.isActive()) __fx.customLobby.rejoinLobby(); else 2===this.a3D?i.ky.a3U():1===this.a3D?i.j(19):i.j(5,5)}`)
 | 
					            if (__fx.customLobby.isActive()) __fx.customLobby.rejoinLobby(); else 2===this.a3D?i.ky.a3U():1===this.a3D?i.j(19):i.j(5,5)}`)
 | 
				
			||||||
        // do not display lobby UI
 | 
					        // do not display lobby UI
 | 
				
			||||||
        replaceRawCode(`(sV.style.backdropFilter="blur(4px)",sV.style.webkitBackdropFilter="blur(4px)"),`,
 | 
					        replaceRawCode(`(sV.style.backdropFilter="blur(4px)",sV.style.webkitBackdropFilter="blur(4px)"),`,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,56 +0,0 @@
 | 
				
			||||||
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) : `
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,10 +1,7 @@
 | 
				
			||||||
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);
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,66 +1,10 @@
 | 
				
			||||||
import { getUIGap } from "./gameInterface.js";
 | 
					 | 
				
			||||||
import { getSettings } from "./settings.js";
 | 
					import { getSettings } from "./settings.js";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const keybindFunctions = {
 | 
					export const keybindFunctions = { setAbsolute: () => {}, setRelative: () => {} };
 | 
				
			||||||
    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;
 | 
				
			||||||
    executeKeybind(keybindData);
 | 
					    if (keybindData.type === "absolute") keybindFunctions.setAbsolute(keybindData.value);
 | 
				
			||||||
 | 
					    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));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
export function KeybindsInput(/** @type {HTMLElement} */ containerElement) {
 | 
					export function KeybindsInput(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,7 +6,6 @@ export function KeybindsInput(/** @type {HTMLElement} */ 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 = [];
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,5 @@
 | 
				
			||||||
const fx_version = '0.6.7.2'; // FX Client Version
 | 
					const fx_version = '0.6.7.1'; // FX Client Version
 | 
				
			||||||
const fx_update = 'Mar 2'; // FX Client Last Updated
 | 
					const fx_update = 'Feb 15'; // 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, mobileKeybinds } from "./keybinds.js";
 | 
					import { keybindFunctions, keybindHandler } from "./keybinds.js";
 | 
				
			||||||
import customLobby from './customLobby.js';
 | 
					import customLobby from './customLobby.js';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
window.__fx = window.__fx || {};
 | 
					window.__fx = window.__fx || {};
 | 
				
			||||||
| 
						 | 
					@ -33,7 +33,6 @@ __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;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -21,7 +21,6 @@ var settings = {
 | 
				
			||||||
  detailedTeamPercentage: false,
 | 
					  detailedTeamPercentage: false,
 | 
				
			||||||
  //"customMapFileBtn": true
 | 
					  //"customMapFileBtn": true
 | 
				
			||||||
  customBackgroundUrl: "",
 | 
					  customBackgroundUrl: "",
 | 
				
			||||||
  keybindButtons: false,
 | 
					 | 
				
			||||||
  attackPercentageKeybinds: [],
 | 
					  attackPercentageKeybinds: [],
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
__fx.settings = settings;
 | 
					__fx.settings = settings;
 | 
				
			||||||
| 
						 | 
					@ -103,10 +102,6 @@ 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)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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(13px + ((0.5 * (1.1vw - 0.1vh)) + 0.14rem));
 | 
						font-size       : calc(14px + ((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,13 +59,6 @@
 | 
				
			||||||
	margin: 0px;
 | 
						margin: 0px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.keybinds-input {
 | 
					 | 
				
			||||||
	margin-bottom: 1em;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
.keybinds-input input {
 | 
					 | 
				
			||||||
	width: 10em;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.flex {
 | 
					.flex {
 | 
				
			||||||
	display: flex;
 | 
						display: flex;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue