Move archives to a separate branch
|
@ -1,32 +0,0 @@
|
||||||
name: Build and Publish to GitHub Pages
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout Repository
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
|
|
||||||
- name: Set up Node.js
|
|
||||||
uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version: '20'
|
|
||||||
|
|
||||||
- name: Install Dependencies
|
|
||||||
run: npm ci
|
|
||||||
|
|
||||||
- name: Build Project
|
|
||||||
run: npm run build
|
|
||||||
|
|
||||||
- name: Deploy to GitHub Pages
|
|
||||||
uses: peaceiris/actions-gh-pages@v3
|
|
||||||
with:
|
|
||||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
publish_dir: ./build
|
|
|
@ -1,4 +0,0 @@
|
||||||
.vscode
|
|
||||||
node_modules
|
|
||||||
game
|
|
||||||
build
|
|
Before Width: | Height: | Size: 15 KiB |
BIN
assets/logo.png
Before Width: | Height: | Size: 50 KiB |
Before Width: | Height: | Size: 91 KiB |
Before Width: | Height: | Size: 103 KiB |
Before Width: | Height: | Size: 99 KiB |
Before Width: | Height: | Size: 17 KiB |
394
build.js
|
@ -1,394 +0,0 @@
|
||||||
const beautify = require('js-beautify').js;
|
|
||||||
const fs = require('fs');
|
|
||||||
|
|
||||||
if (!fs.existsSync("./build")) fs.mkdirSync("./build");
|
|
||||||
fs.cpSync("./static/", "./build/", { recursive: true });
|
|
||||||
fs.cpSync("./assets/", "./build/assets/", { recursive: true });
|
|
||||||
fs.cpSync("./src/fx_core.js", "./build/fx_core.js");
|
|
||||||
fs.writeFileSync("./build/index.html", fs.readFileSync("./build/index.html").toString().replace(/buildTimestamp/g, Date.now()));
|
|
||||||
let script = fs.readFileSync('./game/latest.js', { encoding: 'utf8' }).replace("\n", "").trim();
|
|
||||||
|
|
||||||
const replaceOne = (expression, replaceValue) => {
|
|
||||||
const result = matchOne(expression);
|
|
||||||
// this (below) works correctly because expression.lastIndex gets reset above in matchOne when there is no match
|
|
||||||
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.");
|
|
||||||
let dictionary = {};
|
|
||||||
|
|
||||||
const matchDictionaryExpression = expression => {
|
|
||||||
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;
|
|
||||||
for (let [key, value] of Object.entries(result.groups)) dictionary[key] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return value example:
|
|
||||||
// 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" }
|
|
||||||
const replaceRawCode = (/** @type {string} */ raw, /** @type {string} */ result, nameMappings) => {
|
|
||||||
const { expression, groups } = generateRegularExpression(raw, false, nameMappings);
|
|
||||||
let replacementString = result.replaceAll("$", "$$").replace(/\w+/g, match => {
|
|
||||||
return groups.hasOwnProperty(match) ? "$" + groups[match] : match;
|
|
||||||
});
|
|
||||||
//console.log(replacementString);
|
|
||||||
const expressionMatchResult = replaceOne(expression, replacementString);
|
|
||||||
return Object.fromEntries(Object.entries(groups).map(([identifier, groupNumber]) => [identifier, expressionMatchResult[groupNumber]]));
|
|
||||||
}
|
|
||||||
const matchRawCode = (/** @type {string} */ raw, nameMappings) => {
|
|
||||||
const { expression, groups } = generateRegularExpression(raw, false, nameMappings);
|
|
||||||
const expressionMatchResult = matchOne(expression);
|
|
||||||
return Object.fromEntries(Object.entries(groups).map(([identifier, groupNumber]) => [identifier, expressionMatchResult[groupNumber]]));
|
|
||||||
}
|
|
||||||
const generateRegularExpression = (/** @type {string} */ code, /** @type {boolean} */ isForDictionary, nameMappings) => {
|
|
||||||
const groups = {};
|
|
||||||
let groupNumberCounter = 1;
|
|
||||||
let raw = escapeRegExp(code).replace(isForDictionary ? /(?:@@)*(@?)(\w+)/g : /()(\w+)/g, (_match, modifier, word) => {
|
|
||||||
// if a substitution string for the "word" is specified in the nameMappings, use it
|
|
||||||
if (nameMappings && nameMappings.hasOwnProperty(word)) return nameMappings[word];
|
|
||||||
// if the "word" is a number or is one of these specific words, ingore it
|
|
||||||
if (/^\d/.test(word) || ["return", "this", "var", "function", "Math"].includes(word)) return word;
|
|
||||||
else if (groups.hasOwnProperty(word)) return "\\" + groups[word]; // regex numeric reference to the group
|
|
||||||
else {
|
|
||||||
groups[word] = groupNumberCounter++;
|
|
||||||
return modifier === "@" ? `(?<${word}>\\w+)` : "(\\w+)";
|
|
||||||
}
|
|
||||||
});
|
|
||||||
let expression = new RegExp(isForDictionary ? raw.replaceAll("@@", "@") : raw, "g");
|
|
||||||
return { expression, groups };
|
|
||||||
}
|
|
||||||
|
|
||||||
[
|
|
||||||
///=(?<gIsSingleplayer>\w+)\?"Players":"Bots"/g,
|
|
||||||
/,(?<gIsTeamGame>\w+)=\(\w+=\w+\)<7\|\|9===\w+,/g,
|
|
||||||
/=function\((\w+),(\w+),\w+\){\1===(?<playerId>\w+)\?\w+\(175,\w+\.\w+\(18,\[(?<playerNames>\w+)\[\2\]\]\),1001,\2,\w+\(/g,
|
|
||||||
// this one broke in 1.91.3 /{\w+===(?<playerId>\w+)\?\w+\(175," Message to "/g,
|
|
||||||
/\w+\.\w+\((\w+)\)\?\w+\.\w+\(\1\)\?(\w+)=(\w+\.\w+)\(13,\[\2\]\):\(\w+=\w+\.\w+\(\1\),\2=\3\(14,\[(?<playerNames>\w+)\[(\w+)\],(\w+\.\w+\.\w+\()(?<playerBalances>\w+)\[\5\]\),\6(?<playerTerritories>\w+)\[\5\]\),\2\]\),\w+=!0\):\2=/g,
|
|
||||||
// this one also broke in 1.91.3 /,\w+="Player: "\+(?<playerNames>\w+)\[\w+\],\w+=\(\w\+=" Balance: "\+\w+\.\w+\((?<playerBalances>\w+)\[\w+\]\)\)\+\(" Territory: "\+\w+\.\w+\((?<playerTerritories>\w+)\[\w+\]\)\)\+\(" Coords: "/g,
|
|
||||||
///\((?<uiOffset>\w+)=Math\.floor\(\(\w+\?\.0114:\.01296\)\*\w+\)\)/g,
|
|
||||||
/(function \w+\((\w+),(\w+),(\w+),(\w+),(\w+)\){\6\.fillText\((?<playerNames>\w+)\[\2\],\4,\5\)),(\2<(?<gHumans>\w+)&&2!==(?<playerStates>\w+)\[)/g,
|
|
||||||
/,\w+=512,(?<gLobbyMaxJoin>\w+)=\w+,(?<gIsSingleplayer>\w+)&&\(\1=\w+\.\w+\(\)\),\w+=\1-\w+,\w+=0,/g,
|
|
||||||
/function \w+\(\)\{if\(2===(?<gameState>\w+)\)return 1;\w+\.\w+\(\),\1=2,\w+=\w+\}/g
|
|
||||||
].forEach(matchDictionaryExpression);
|
|
||||||
|
|
||||||
const rawCodeSegments = [
|
|
||||||
"[0]=aV.nU[70],a0T[1]=@gIsSingleplayer?aV.nU[71]:aV.nU[72],",
|
|
||||||
"?(this.gB=Math.floor(.0536*aK.fw),g5=aK.g5-4*@uiSizes.@gap-this.gB):"
|
|
||||||
]
|
|
||||||
|
|
||||||
rawCodeSegments.forEach(code => {
|
|
||||||
const { expression } = generateRegularExpression(code, true);
|
|
||||||
//console.log(expression);
|
|
||||||
matchDictionaryExpression(expression);
|
|
||||||
});
|
|
||||||
|
|
||||||
fs.writeFileSync("./build/fx_core.js", `const dictionary = ${JSON.stringify(dictionary)};\n` + fs.readFileSync("./build/fx_core.js").toString());
|
|
||||||
|
|
||||||
// Replace assets
|
|
||||||
const assets = require('./assets.js');
|
|
||||||
replaceOne(/(\(4,"crown",4,")[^"]+"\),/g, "$1" + assets.crownIcon + "\"),");
|
|
||||||
replaceOne(/(\(6,"territorial\.io",6,")[^"]+"\),/g, "$1" + assets.fxClientLogo + "\"),");
|
|
||||||
|
|
||||||
/*// Add FXClient menu item in "More" menu
|
|
||||||
// match },ug[0][5]={name:a79,id:5,mf:90,oU:0,e8:0},
|
|
||||||
replaceOne(/(},(\w+\[0\])\[\d+\]={(\w+):\w+,(\w+):\d+,(\w+):90,(\w+):0,(\w+):0},)/g,
|
|
||||||
'$1$2.push({$3:"FX Client v" + fx_version + " " + fx_update, $4: 20, $5: 0, $6: 0, $7: 70}),');
|
|
||||||
// Do not display hover effect on the last 2 items (territorial.io version and FX Client version) instead of only the last item
|
|
||||||
// match 0 === a9P ? ug[a9P].length - 1 : ug[a9P].length : 1,
|
|
||||||
replaceOne(/(0===(\w+)\?(\w+)\[\2\]\.length)-1:(\3\[\2\]\.length:1,)/g, "$1 - 2 : $4");*/
|
|
||||||
// Add FX Client version info to the game version window
|
|
||||||
//replaceRawCode(`ar.aAx("MenuGameVersion")||ar.aAz(new aB3("ℹ️ "+aV.nU[84],gameVersion+"<br><a href='"`,
|
|
||||||
replaceRawCode(`ar.oa(4,1,new s8("ℹ️ "+Translations.txt[84],gameVersion+"<br><a href='"+ah.aC5+"' target='_blank'>"+ah.aC5+"</a>",`,
|
|
||||||
`ar.oa(4,1,new s8("ℹ️ "+Translations.txt[84],gameVersion+"<br><a href='"+ah.aC5+"' target='_blank'>"+ah.aC5+"</a>"
|
|
||||||
+ "<br><br><b>" + "FX Client v" + fx_version + " " + fx_update + "<br><a href='https://discord.gg/dyxcwdNKwK' target='_blank'>FX Client Discord server</a>"
|
|
||||||
+ "<br><a href='https://github.com/fxclient/FXclient' target='_blank'>Github repository</a></b>",`);
|
|
||||||
|
|
||||||
// Max size for custom maps: from 4096x4096 to 8192x8192
|
|
||||||
// TODO: test this; it might cause issues with new boat mechanics?
|
|
||||||
|
|
||||||
{ // Add Troop Density and Maximum Troops in side panel
|
|
||||||
/*const { groups: { valuesArray } } = replaceOne(/(,(?<labelsArray>\w+)\[\d\]="Interest",\2\[\d\]="Income",\2\[\d\]="Time"),(\w+=\w+-\w+\(\w+,100\),\((?<valuesArray>\w+)=new Array\(\2\.length\)\)\[0\]=\w+)/g,
|
|
||||||
'$1, $<labelsArray>.push("Max Troops", "Density"), $3'); // add labels*/
|
|
||||||
const { valuesArray } = replaceRawCode(`,labels[5]=aV.nU[76],labels[6]=aV.nU[77],labels[7]=aV.nU[78],a0Z=tn-eT(tn,100),(valuesArray=new Array(labels.length))[0]=io?`,
|
|
||||||
`,labels[5]=aV.nU[76],labels[6]=aV.nU[77],labels[7]=aV.nU[78],
|
|
||||||
labels.push("Max Troops", "Density"), // add labels
|
|
||||||
a0Z=tn-eT(tn,100),(valuesArray=new Array(labels.length))[0]=io?`);
|
|
||||||
replaceOne(new RegExp(/(:(?<valueIndex>\w+)<7\?\w+\.\w+\.\w+\(valuesArray\[\2\]\)):(\w+\.\w+\(valuesArray\[7\]\))}/
|
|
||||||
.source.replace(/valuesArray/g, valuesArray), "g"),
|
|
||||||
'$1 : $<valueIndex> === 7 ? $3 '
|
|
||||||
+ `: $<valueIndex> === 8 ? utils.getMaxTroops(${dictionary.playerTerritories}, ${dictionary.playerId}) `
|
|
||||||
+ `: utils.getDensity(${dictionary.playerId}) }`);
|
|
||||||
// increase the size of the side panel by 25% to make the text easier to read
|
|
||||||
replaceOne(/(this\.\w+=Math\.floor\(\(\w+\.\w+\.\w+\(\)\?\.1646:\.126\))\*(\w+\.\w+\),)/g, "$1 * 1.25 * $2");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Increment win counter on wins
|
|
||||||
/*replaceOne(/(=function\((\w+)\){)([^}]+),((\w+\(0),\w+<100\?(\w+\.\w+)\(11,(\[\w+\[\w+\]\])\):\6\(12,\7\),(3,\2,[^()]+?\))),(?<end>[^}]+},)/g,
|
|
||||||
`$1 if (${dictionary.playerId} === $2) wins_counter++, window.localStorage.setItem("fx_winCount", wins_counter); ` +
|
|
||||||
`$3, $4, $5, "Your Current Win Count is Now " + wins_counter, $8, $<end>`);*/
|
|
||||||
replaceRawCode(`=function(rC){n.hQ(rC,2),vm(0,h2<100?aV.s9(4,[jm[rC]]):aV.s9(12,[jm[rC]]),3,rC,aZ.gG,aZ.ka,-1,!0),`,
|
|
||||||
`=function(rC){
|
|
||||||
if (${dictionary.playerId} === rC && !${dictionary.gIsSingleplayer})
|
|
||||||
wins_counter++, window.localStorage.setItem("fx_winCount", wins_counter),
|
|
||||||
vm(0,"Your Win Count is now " + wins_counter,3,rC,aZ.gG,aZ.ka,-1,!0);
|
|
||||||
n.hQ(rC,2),vm(0,h2<100?aV.s9(4,[jm[rC]]):aV.s9(12,[jm[rC]]),3,rC,aZ.gG,aZ.ka,-1,!0),`);
|
|
||||||
|
|
||||||
|
|
||||||
{ // Add settings button and win count
|
|
||||||
// render gear icon and win count
|
|
||||||
/*// cV.textAlign=cX,cV.textBaseline=cW,a03(a9Y.gb,a9Y.gc,a9Y.m5,a9Y.tD,ug[a9P][0].mf,ug[a9P][0].oU,ug[a9P][0].e8,0===yk,ug[a9P][0].name),a9O))
|
|
||||||
// l(A.f3, A.f4, A.hw, A.nI, z[0].f7, z[0].mx, z[0].cm, 0 === t, z[0].name, .6);
|
|
||||||
// cH.drawImage(settingsGearIcon,A.f3-A.hw/2,A.f4,A.nI,A.nI);
|
|
||||||
// cH.font = bt + Math.floor(A.nI * 0.4) + bu;
|
|
||||||
// cH.fillText("Win count: " + wins_counter, Math.floor(A.f3 + A.hw / 2), Math.floor((A.f4 + A.nI / 2) * 2.1));
|
|
||||||
const { groups } = replaceOne(/((?<canvas>\w+)\.textAlign=\w+,\2\.textBaseline=\w+,\w+\((?<x>(?<coords>\w+).\w+),(?<y>\4.\w+),(?<w>\4.\w+),(?<h>\4.\w+),[^)]+\)),(?<end>(?<isMenuOpened>\w+)\)\))/g, '$1, ' +
|
|
||||||
'$<canvas>.imageSmoothingEnabled = true, ' +
|
|
||||||
'$<canvas>.drawImage(settingsGearIcon, $<x>-$<w>/2, $<y>, $<h>, $<h>), ' +
|
|
||||||
'$<canvas>.imageSmoothingEnabled = false, ' +
|
|
||||||
'$<canvas>.font = "bold " + Math.floor($<h> * 0.4) + "px " + settings.fontName, ' +
|
|
||||||
'(settings.displayWinCounter && !$<isMenuOpened> && $<canvas>.fillText("Win count: " + wins_counter, Math.floor($<x> + $<w> / 2), Math.floor(($<y> + $<h> / 2) * 2.1))), ' +
|
|
||||||
'$<end>');*/
|
|
||||||
replaceRawCode(`,fy=aV.nU[80],fontSize=.65*height,canvas.font=aY.g0.g1(1,fontSize),canvas.fillStyle="rgba("+gR+","+tD+","+hj+",0.6)",canvas.fillRect(x,y,width,height),`,
|
|
||||||
`,fy=aV.nU[80],fontSize=.65*height,
|
|
||||||
canvas.imageSmoothingEnabled = true,
|
|
||||||
canvas.drawImage(settingsGearIcon, x - width / 2, y, height, height),
|
|
||||||
canvas.imageSmoothingEnabled = false,
|
|
||||||
(settings.displayWinCounter && (
|
|
||||||
canvas.font = aY.g0.g1(1, Math.floor(height * 0.4)),
|
|
||||||
canvas.fillStyle = "#ffffff",
|
|
||||||
canvas.fillText("Win count: " + wins_counter, Math.floor(x + width / 2), Math.floor((y + height / 2) * 2))
|
|
||||||
)),
|
|
||||||
canvas.font=aY.g0.g1(1,fontSize),canvas.fillStyle="rgba("+gR+","+tD+","+hj+",0.6)",canvas.fillRect(x,y,width,height),`);
|
|
||||||
|
|
||||||
// handle settings button click
|
|
||||||
/*replaceOne(/(this\.\w+=function\((?<mouseX>\w+),(?<mouseY>\w+)\){[^}]+?)if\((?<coordsGet>\w+=\w+\(\)),(?<isMenuOpened>\w+)\)(?<end>{for\([^}]+"Lobby ")/g,
|
|
||||||
'$1 $<coordsGet>; ' +
|
|
||||||
`var gearIconX = ${groups.x}-${groups.w}/2; ` +
|
|
||||||
// if (y > (C.f3-C.hw/2) && y < ((C.f3-C.hw/2)+C.nI) && A > C.f4 && A < (C.f4 + C.nI)) WindowManager.openWindow("settings");
|
|
||||||
`if ($<mouseX> > gearIconX && $<mouseX> < (gearIconX+${groups.h}) && $<mouseY> > ${groups.y} && $<mouseY> < (${groups.y}+${groups.h})) return WindowManager.openWindow("settings"); ` +
|
|
||||||
'if ($<isMenuOpened>) $<end>');*/
|
|
||||||
replaceRawCode(`(q6=Math.floor((b7.cv.fv()?.145:.09)*aK.fw),gap=Math.floor(.065*(b7.cv.fv()?.53:.36)*aK.fw),gap=aK.g5-q6-gap,jd=b0.gap,q6=Math.floor(.35*q6),gap<=mouseX&&mouseY<jd+q6&&ar.v2(1))`,
|
|
||||||
`(q6=Math.floor((b7.cv.fv()?.145:.09)*aK.fw),gap=Math.floor(.065*(b7.cv.fv()?.53:.36)*aK.fw),gap=aK.g5-q6-gap,jd=b0.gap,q6=Math.floor(.35*q6),
|
|
||||||
(gap <= mouseX && mouseY < jd + q6 && (ar.v2(1), true)) || (mouseX >= gap - q6 / 0.7 && mouseY < jd + q6 && WindowManager.openWindow("settings"))
|
|
||||||
)`);
|
|
||||||
}
|
|
||||||
|
|
||||||
{ // Keybinds
|
|
||||||
// match required variables
|
|
||||||
const { 0: match, groups: { attackBarObject, setRelative } } = matchOne(/:"."===(\w+\.key)\?(?<attackBarObject>\w+)\.(?<setRelative>\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===(?<attackPercentage>\w+)\|\|\(1<\2&&\2\*\3-\3<1\/1024\?\2=\(\3\+1\/1024\)\/\3:\2<1)/g,
|
|
||||||
"} this.setAbsolutePercentage = function(newPercentage) { $<attackPercentage> = 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+\((?<event>\w+)\){)([^}]+matched)/g.source.replace(/matched/g, escapeRegExp(match)), "g"),
|
|
||||||
"$1 if (keybindHandler($<event>.key)) return; $3");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the default font to Trebuchet MS
|
|
||||||
script = script.replace(/sans-serif"/g, 'Trebuchet MS"');
|
|
||||||
|
|
||||||
// Realistic bot names setting
|
|
||||||
// matches c4[i] = c4[i].replace(a6U[dx], a6V[dx])
|
|
||||||
replaceOne(/(((\w+)\[\w+\])=\2\.replace\(\w+(\[\w+\]),\w+\4\))/g, "$1; if (settings.realisticNames) $3 = realisticNames;")
|
|
||||||
|
|
||||||
// Hide all links in main menu depending on settings
|
|
||||||
//replaceOne(/(this\.\w+=function\(\){)((\w+\.\w+)\[2\]=\3\[3\]=\3\[4\]=(?<linksHidden>!this\.\w+\.\w+),)/g,
|
|
||||||
//"$1 if (settings.hideAllLinks) $3[0] = $3[1] = $<linksHidden>; else $3[0] = $3[1] = true; $2")
|
|
||||||
|
|
||||||
// Make the main canvas context have an alpha channel if a custom background is being used
|
|
||||||
replaceOne(/(document\.getElementById\("canvasA"\),\(\w+=\w+\.getContext\("2d",){alpha:!1}/g, "$1 {alpha: makeMainMenuTransparent}")
|
|
||||||
// Clear canvas background if a custom background is being used
|
|
||||||
replaceOne(/(this\.\w+=function\(\){var (\w+),(\w+);)(\w+\.\w+\?\([^()]+setTransform\(\3=\2<\3\?\3:\2,0,0,\3,(?:Math\.floor\(\([^)]+\)\/2\)[,)]){2},(?:[^)]+\),){2}[^)]+\):(?<canvas>\w+)\.fillStyle=\w+\.\w+,\5\.fillRect\((?<wholeCanvas>0,0,\w+\.\w+,\w+\.\w+)\)}})/g,
|
|
||||||
'$1 if (makeMainMenuTransparent) $<canvas>.clearRect($<wholeCanvas>); else $4')
|
|
||||||
|
|
||||||
// Track donations
|
|
||||||
replaceOne(/(this\.\w+=function\((\w+),(\w+)\)\{)(\2===\w+&&\(\w+\.\w+\((\w+\.\w+)\[0\],\5\[1\],\3\),this\.(\w+)\[12\]\+=\5\[1\],this\.\6\[16\]\+=\5\[0\]\),\3===\w+&&\()/g,
|
|
||||||
"$1 donationsTracker.logDonation($2, $3, $5[0]); $4")
|
|
||||||
|
|
||||||
// Display donations for a player when clicking on them in the leaderboard
|
|
||||||
// and skip handling clicks when clicking on an empty space (see the isEmptySpace
|
|
||||||
// variable in the modified leaderboard click handler from the leaderboard filter)
|
|
||||||
// match , 0 !== dG[x]) && fq.hB(x, 800, false, 0),
|
|
||||||
replaceOne(/,(0!==\w+\[(\w+)\])(\)&&\w+\.\w+\(\2,800,!1,0\),)/g,
|
|
||||||
`, ${dictionary.gIsTeamGame} && donationsTracker.displayHistory($2, ${dictionary.playerNames}, ${dictionary.gIsSingleplayer}), $1 && !isEmptySpace $3`);
|
|
||||||
|
|
||||||
// Reset donation history and leaderboard filter when a new game is started
|
|
||||||
replaceOne(new RegExp(`,${dictionary.playerBalances}=new Uint32Array\\(\\w+\\),`, "g"), "$& donationsTracker.reset(), leaderboardFilter.reset(), ");
|
|
||||||
|
|
||||||
{ // Player list and leaderboard filter tabs
|
|
||||||
// Draw player list button
|
|
||||||
const uiOffset = dictionary.uiSizes + "." + dictionary.gap;
|
|
||||||
const { groups: { drawFunction, topBarHeight } } = replaceOne(/(=1;function (?<drawFunction>\w+)\(\){[^}]+?(?<canvas>\w+)\.fillRect\(0,(?<topBarHeight>\w+),\w+,1\),(?:\3\.fillRect\([^()]+\),)+\3\.font=\w+,(\w+\.\w+)\.textBaseline\(\3,1\),\5\.textAlign\(\3,1\),\3\.fillText\(\w+\.\w+\[65\],Math\.floor\()(\w+)\/2\),(Math\.floor\(\w+\+\w+\/2\)\));/g,
|
|
||||||
"$1($6 + $<topBarHeight> - 22) / 2), $7; playerList.drawButton($<canvas>, 12, 12, $<topBarHeight> - 22);");
|
|
||||||
const buttonBoundsCheck = `utils.isPointInRectangle($<x>, $<y>, ${uiOffset} + 12, ${uiOffset} + 12, ${topBarHeight} - 22, ${topBarHeight} - 22)`
|
|
||||||
// Handle player list button and leaderboard tabs mouseDown
|
|
||||||
// and create a function for scrolling the leaderboard to the top
|
|
||||||
replaceOne(/(this\.\w+=function\((?<x>\w+),(?<y>\w+)\){return!!\w+\(\2,\3\))&&(\(\w+=\w+\.\w+,[^}]+),!0\)/g,
|
|
||||||
`leaderboardFilter.scrollToTop = function(){position = 0;}, $1 && ((${buttonBoundsCheck} && playerList.display(${dictionary.playerNames}), true)
|
|
||||||
&& !($<y> - ${uiOffset} > leaderboardFilter.verticalClickThreshold && leaderboardFilter.handleMouseDown($<x> - ${uiOffset})) && $4),!0)`);
|
|
||||||
// Handle player list button and leaderboard tabs hover
|
|
||||||
// and create a function for repainting the leaderboard
|
|
||||||
replaceOne(/(this\.\w+=function\((?<x>\w+),(?<y>\w+)\){)(var \w+,\w+=\w+\(\3\);return \w+\?\(\w+=(\w+),\(\5=\w+\(0,\5\+=(?:[^}]+,(?<setRepaintNeeded>\w+\.\w+=!0)){2})/g,
|
|
||||||
`leaderboardFilter.repaintLeaderboard = function() { ${drawFunction}(), $<setRepaintNeeded>; },
|
|
||||||
$1 if (${buttonBoundsCheck}) { playerList.hoveringOverButton === false && (playerList.hoveringOverButton = true, ${drawFunction}(), $<setRepaintNeeded>); }
|
|
||||||
else { playerList.hoveringOverButton === true && (playerList.hoveringOverButton = false, ${drawFunction}(), $<setRepaintNeeded>); }
|
|
||||||
if (leaderboardFilter.setHovering(
|
|
||||||
utils.isPointInRectangle($<x>, $<y>, ${uiOffset}, ${uiOffset} + leaderboardFilter.verticalClickThreshold, leaderboardFilter.windowWidth, leaderboardFilter.tabBarOffset), $<x> - ${uiOffset}
|
|
||||||
)) return; $4`);
|
|
||||||
}
|
|
||||||
|
|
||||||
{ // Display density of other players
|
|
||||||
// Applies when the "Reverse Name/Balance" setting is off
|
|
||||||
const { groups: { settingsSwitchNameAndBalance } } = replaceOne(/(,(?<settingsSwitchNameAndBalance>\w+\.\w+\.\w+\[7\]\.\w+)\?(?<nameDrawingFunction>\w+)\(\w+,\w+,(?<x>\w+),(?<y>\w+)\+\.78\*(?<fontSize>\w+),(?<canvas>\w+)\)):(\7\.fillText\(\w+\.\w+\.\w+\(\w+\[(\w+)\]\),\4,\5\+\.78\*\6\))\)\)/g,
|
|
||||||
`$1 : ($8, settings.showPlayerDensity && (settings.coloredDensity && ($<canvas>.fillStyle = utils.textStyleBasedOnDensity($9)), $<canvas>.fillText(utils.getDensity($9), $<x>, $<y> + $<fontSize> * 1.5)) ) ) )`);
|
|
||||||
// Applies when the "Reverse Name/Balance" setting is on (default)
|
|
||||||
replaceOne(/(function \w+\((\w+),(?<fontSize>\w+),(?<x>\w+),(?<y>\w+),(?<canvas>\w+)\){)(\6\.fillText\((?<playerNames>\w+)\[\2\],\4,\5\)),(\2<(?<gHumans>\w+)&&2!==(?<playerStates>\w+)\[[^}]+)}/g,
|
|
||||||
`$1 var ___id = $2; $7, $9; ${settingsSwitchNameAndBalance} && settings.showPlayerDensity && (settings.coloredDensity && ($<canvas>.fillStyle = utils.textStyleBasedOnDensity(___id)), $<canvas>.fillText(utils.getDensity(___id), $<x>, $<y> + $<fontSize>)); }`);
|
|
||||||
}
|
|
||||||
|
|
||||||
{ // Leaderboard filter
|
|
||||||
// for the leaderboard draw function:
|
|
||||||
replaceRawCode("a0A.clearRect(0,0,a04,y9),a0A.fillStyle=aZ.lE,a0A.fillRect(0,0,a04,a0F),a0A.fillStyle=aZ.kZ,a0A.fillRect(0,a0F,a04,y9-a0F),leaderboardPositionsById[playerId]>=position&&a0Z(leaderboardPositionsById[playerId]-position,aZ.kw),0!==leaderboardPositionsById[playerId]&&0===position&&a0Z(0,aZ.lJ),-1!==a0P&&a0Z(a0P,aZ.kd),a0A.fillStyle=aZ.gF,a0A.fillRect(0,a0F,a04,1),a0A.fillRect(0,0,a04,b0.ur),a0A.fillRect(0,0,b0.ur,y9),a0A.fillRect(a04-b0.ur,0,b0.ur,y9),a0A.fillRect(0,y9-b0.ur,a04,b0.ur),",
|
|
||||||
`a0A.clearRect(0, 0, a04, y9),
|
|
||||||
a0A.fillStyle = aZ.lE,
|
|
||||||
a0A.fillRect(0, 0, a04, a0F),
|
|
||||||
a0A.fillStyle = aZ.kZ,
|
|
||||||
a0A.fillRect(0, a0F, a04, y9 - a0F);
|
|
||||||
if (leaderboardFilter.enabled) {
|
|
||||||
leaderboardFilter.filteredLeaderboard = leaderboardFilter.playersToInclude
|
|
||||||
.map(id => leaderboardPositionsById[id]).sort((a, b) => a - b);
|
|
||||||
}
|
|
||||||
var playerPos = (leaderboardFilter.enabled
|
|
||||||
? leaderboardFilter.filteredLeaderboard.indexOf(leaderboardPositionsById[playerId])
|
|
||||||
: leaderboardPositionsById[playerId]
|
|
||||||
);
|
|
||||||
this.playerPos = playerPos;
|
|
||||||
if (leaderboardFilter.hoveringOverTabs) a0P = -1;
|
|
||||||
if (leaderboardFilter.enabled && a0P >= leaderboardFilter.filteredLeaderboard.length) a0P = -1;
|
|
||||||
playerPos >= position && a0Z(playerPos - position, aZ.kw),
|
|
||||||
0 !== leaderboardPositionsById[playerId] && 0 === position && a0Z(0, aZ.lJ),
|
|
||||||
-1 !== a0P && a0Z(a0P, aZ.kd),
|
|
||||||
a0A.fillStyle = aZ.kZ,
|
|
||||||
//console.log("drawing", a0P),
|
|
||||||
a0A.clearRect(0, y9 - leaderboardFilter.tabBarOffset, a04, leaderboardFilter.tabBarOffset);
|
|
||||||
a0A.fillRect(0, y9 - leaderboardFilter.tabBarOffset, a04, leaderboardFilter.tabBarOffset);
|
|
||||||
a0A.fillStyle = aZ.gF,
|
|
||||||
a0A.fillRect(0, a0F, a04, 1),
|
|
||||||
a0A.fillRect(0, y9 - leaderboardFilter.tabBarOffset, a04, 1),
|
|
||||||
leaderboardFilter.drawTabs(a0A, a04, y9 - leaderboardFilter.tabBarOffset, aZ.kw),
|
|
||||||
a0A.fillRect(0, 0, a04, b0.ur),
|
|
||||||
a0A.fillRect(0, 0, b0.ur, y9),
|
|
||||||
a0A.fillRect(a04 - b0.ur, 0, b0.ur, y9),
|
|
||||||
a0A.fillRect(0, y9 - b0.ur, a04, b0.ur),`)
|
|
||||||
replaceRawCode("var hZ,eh=leaderboardPositionsById[playerId]<position+windowHeight-1?1:2;for(a0A.font=a07,aY.g0.textAlign(a0A,0),hZ=windowHeight-eh;0<=hZ;hZ--)a0a(leaderboardArray[hZ+position]),a0b(hZ,hZ+position,leaderboardArray[hZ+position]);for(aY.g0.textAlign(a0A,2),hZ=windowHeight-eh;0<=hZ;hZ--)a0a(leaderboardArray[hZ+position]),a0c(hZ,leaderboardArray[hZ+position]);",
|
|
||||||
`var hZ, eh = playerPos < position + windowHeight - 1 ? 1 : 2;
|
|
||||||
|
|
||||||
if (leaderboardFilter.enabled) {
|
|
||||||
let result = leaderboardFilter.filteredLeaderboard;
|
|
||||||
if (position !== 0 && position >= result.length - windowHeight)
|
|
||||||
position = (result.length > windowHeight ? result.length : windowHeight) - windowHeight;
|
|
||||||
//if (position >= result.length) position = result.length - 1;
|
|
||||||
for (a0A.font = a07, aY.g0.textAlign(a0A, 0), hZ = windowHeight - eh; 0 <= hZ; hZ--) {
|
|
||||||
const pos = result[hZ + position];
|
|
||||||
if (pos !== undefined)
|
|
||||||
a0a(leaderboardArray[pos]), a0b(hZ, pos, leaderboardArray[pos]);
|
|
||||||
}
|
|
||||||
for (aY.g0.textAlign(a0A, 2), hZ = windowHeight - eh; 0 <= hZ; hZ--) {
|
|
||||||
const pos = result[hZ + position];
|
|
||||||
if (pos !== undefined)
|
|
||||||
a0a(leaderboardArray[pos]), a0c(hZ, leaderboardArray[pos]);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (a0A.font = a07, aY.g0.textAlign(a0A, 0), hZ = windowHeight - eh; 0 <= hZ; hZ--)
|
|
||||||
a0a(leaderboardArray[hZ + position]), a0b(hZ, hZ + position, leaderboardArray[hZ + position]);
|
|
||||||
for (aY.g0.textAlign(a0A, 2), hZ = windowHeight - eh; 0 <= hZ; hZ--)
|
|
||||||
a0a(leaderboardArray[hZ + position]), a0c(hZ, leaderboardArray[hZ + position]);
|
|
||||||
}`)
|
|
||||||
// in the leaderboard resize handler: make space for the tab buttons at the bottom of the leaderboard
|
|
||||||
replaceRawCode(",a0D=.025*a04,a06=.16*a04,a0E=0*a04,a0F=Math.floor(.45*a0D+a06),a0G=(y9-a06-2*a0D-a0E)/a08,a05=aY.g0.g1(1,Math.floor(.55*a06)),",
|
|
||||||
`,a0D=.025*a04,a06=.16*a04,a0E=0*a04,a0F=Math.floor(.45*a0D+a06),a0G=(y9-a06-2*a0D-a0E)/a08,
|
|
||||||
a09.height = y9 += a0G, leaderboardFilter.tabBarOffset = Math.floor(a0G * 1.3), leaderboardFilter.verticalClickThreshold = y9 - leaderboardFilter.tabBarOffset, leaderboardFilter.windowWidth = a04,
|
|
||||||
a05=aY.g0.g1(1,Math.floor(.55*a06)),`)
|
|
||||||
// handle clicking on a player in the leaderboard
|
|
||||||
replaceRawCode("var a0p=a0q(fJ);return ag.tQ()&&-1!==a0P&&(a0P=-1,a0Y(),b3.d1=!0),b3.dY-a0Q<350&&a0T===a0p&&-1!==(a0p=(a0p=yr(-1,a0p,windowHeight))!==windowHeight&&vU(x,y)?a0p:-1)&&(x=leaderboardArray[a0p+position],a0p===windowHeight-1&&leaderboardPositionsById[playerId]>=position+windowHeight-1&&(x=playerId),",
|
|
||||||
`var a0p = a0q(fJ);
|
|
||||||
var isEmptySpace = false;
|
|
||||||
return ag.tQ() && -1 !== a0P && (a0P = -1, a0Y(), b3.d1 = !0), b3.dY - a0Q < 350 && a0T === a0p && -1 !== (a0p = (a0p = yr(-1, a0p, windowHeight)) !== windowHeight && vU(x, y) ? a0p : -1) && (x = (leaderboardFilter.enabled ? leaderboardArray[leaderboardFilter.filteredLeaderboard[a0p + position] ?? (isEmptySpace = true, leaderboardPositionsById[playerId])] : leaderboardArray[a0p + position]), a0p === windowHeight - 1 && (leaderboardFilter.enabled ? this.playerPos : leaderboardPositionsById[playerId]) >=
|
|
||||||
position + windowHeight - 1 && (x = playerId), !isEmptySpace && `);
|
|
||||||
}
|
|
||||||
|
|
||||||
{ // Hovering tooltip
|
|
||||||
replaceRawCode("this.click=function(g8,g9,tE){var fT=aj.fU(g8),fV=aj.fW(g9),fX=aj.fY(fT,fV),fZ=aj.fa(fX);return!(!aj.fb(fT,fV)||(fT=(b7.cv.fv()?.025:.0144)*aK.fw,fV=performance.now(),Math.abs(g8-uu)>fT)||Math.abs(g9-uv)>fT||dY+500<fV)&&(dY=fV,tE?(function(g8,g9,fZ){a2.eb(fZ)||-1===(g8=ak.ff.vR(g8,g9))?k.vQ(fZ):k.vS(g8)}(g8,g9,fZ),!1)",
|
|
||||||
`hoveringTooltip.display = function(mouseX, mouseY) {
|
|
||||||
var coordX = aj.fU(mouseX), coordY = aj.fW(mouseY),
|
|
||||||
coord = aj.fY(coordX, coordY), point = aj.fa(coord);
|
|
||||||
if (coordX < 0 || coordY < 0) return;
|
|
||||||
k.vQ(point);
|
|
||||||
}
|
|
||||||
this.click = function(g8, g9, tE) {
|
|
||||||
var fT = aj.fU(g8),
|
|
||||||
fV = aj.fW(g9),
|
|
||||||
fX = aj.fY(fT, fV),
|
|
||||||
fZ = aj.fa(fX);
|
|
||||||
return !(!aj.fb(fT, fV) || (fT = (b7.cv.fv() ? .025 : .0144) * aK.fw, fV = performance.now(), Math.abs(g8 - uu) > fT) || Math.abs(g9 - uv) > fT || dY + 500 < fV) && (dY = fV, tE ? (function(g8, g9, fZ) {
|
|
||||||
a2.eb(fZ) || -1 === (g8 = ak.ff.vR(g8, g9)) ? k.vQ(fZ) : k.vS(g8)
|
|
||||||
}(g8, g9, fZ), false)`)
|
|
||||||
replaceRawCode("aK.nH=(window.devicePixelRatio||1)*aEr,",
|
|
||||||
`aK.nH = (window.devicePixelRatio || 1) * aEr, hoveringTooltip.canvasPixelScale = aK.nH,`)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Disable built-in Territorial.io error reporting
|
|
||||||
replaceOne(/window\.addEventListener\("error",function (\w+)\((\w+)\){/g,
|
|
||||||
'$& window.removeEventListener("error", $1); return alert("Error:\\n" + $2.filename + " " + $2.lineno + " " + $2.colno + " " + $2.message);');
|
|
||||||
|
|
||||||
console.log('Removing ads...');
|
|
||||||
// Remove ads
|
|
||||||
script = script.replace('//api.adinplay.com/libs/aiptag/pub/TRT/territorial.io/tag.min.js','');
|
|
||||||
|
|
||||||
console.log("Formatting code...");
|
|
||||||
|
|
||||||
exposeVarsToGlobalScope = true;
|
|
||||||
|
|
||||||
if (exposeVarsToGlobalScope && script.startsWith("\"use strict\"; (function () {") && script.endsWith("})();"))
|
|
||||||
script = script.slice("\"use strict\"; (function () {".length, -"})();".length);
|
|
||||||
if (exposeVarsToGlobalScope && script.startsWith("(function () {") && script.endsWith("})();"))
|
|
||||||
script = script.slice("(function () {".length, -"})();".length);
|
|
||||||
|
|
||||||
script = beautify(script, {
|
|
||||||
"indent_size": "1",
|
|
||||||
"indent_char": "\t",
|
|
||||||
"max_preserve_newlines": "5",
|
|
||||||
"preserve_newlines": true,
|
|
||||||
"keep_array_indentation": false,
|
|
||||||
"break_chained_methods": false,
|
|
||||||
"indent_scripts": "normal",
|
|
||||||
"brace_style": "collapse",
|
|
||||||
//"brace_style": "expand",
|
|
||||||
"space_before_conditional": true,
|
|
||||||
"unescape_strings": false,
|
|
||||||
"jslint_happy": false,
|
|
||||||
"end_with_newline": false,
|
|
||||||
"wrap_line_length": "250",
|
|
||||||
"indent_inner_html": false,
|
|
||||||
"comma_first": false,
|
|
||||||
"e4x": false,
|
|
||||||
"indent_empty_lines": false
|
|
||||||
});
|
|
||||||
|
|
||||||
fs.writeFileSync("./build/game.js", script);
|
|
||||||
console.log("Wrote ./build/game.js");
|
|
||||||
console.log("Build done");
|
|
35
download.js
|
@ -1,35 +0,0 @@
|
||||||
const downloadGame = () => new Promise(resolve => {
|
|
||||||
// Download game
|
|
||||||
// https://stackoverflow.com/a/11944984
|
|
||||||
const https = require('https'); // or 'https' for https:// URLs
|
|
||||||
const fs = require('fs');
|
|
||||||
|
|
||||||
if (!fs.existsSync("./game")) fs.mkdirSync("./game");
|
|
||||||
const file = fs.createWriteStream("./game/latest.html");
|
|
||||||
// Download the game's code from the website
|
|
||||||
const request = https.get("https://territorial.io", function (response) {
|
|
||||||
// and save it to ./game/latest.html
|
|
||||||
response.pipe(file);
|
|
||||||
|
|
||||||
// after download completed close filestream
|
|
||||||
file.on("finish", () => {
|
|
||||||
file.close();
|
|
||||||
console.log("Download Completed [downloaded to latest.html]");
|
|
||||||
fs.readFile('./game/latest.html', 'utf8', function (err, data) {
|
|
||||||
if (err) throw err;
|
|
||||||
// Extract the game script from the html
|
|
||||||
// https://stackoverflow.com/a/14867897
|
|
||||||
const scriptContent = data.substring(
|
|
||||||
data.indexOf("<script>") + "<script>".length,
|
|
||||||
data.lastIndexOf("</script>")
|
|
||||||
);
|
|
||||||
// Write the script to ./game/latest.js without any line breaks
|
|
||||||
fs.writeFileSync("./game/latest.js", scriptContent.replace(/\r?\n|\r/g, ""));
|
|
||||||
console.log("Wrote script to latest.js");
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
module.exports = downloadGame;
|
|
2
index.js
|
@ -1,2 +0,0 @@
|
||||||
console.log("Building FXClient");
|
|
||||||
require("./download.js")().then(() => require("./build.js"));
|
|
|
@ -1,953 +0,0 @@
|
||||||
{
|
|
||||||
"name": "fxclient",
|
|
||||||
"version": "0.5.3",
|
|
||||||
"lockfileVersion": 2,
|
|
||||||
"requires": true,
|
|
||||||
"packages": {
|
|
||||||
"": {
|
|
||||||
"name": "fxclient",
|
|
||||||
"version": "0.5.3",
|
|
||||||
"license": "ISC",
|
|
||||||
"dependencies": {
|
|
||||||
"js-beautify": "^1.14.11"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@isaacs/cliui": {
|
|
||||||
"version": "8.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
|
|
||||||
"integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
|
|
||||||
"dependencies": {
|
|
||||||
"string-width": "^5.1.2",
|
|
||||||
"string-width-cjs": "npm:string-width@^4.2.0",
|
|
||||||
"strip-ansi": "^7.0.1",
|
|
||||||
"strip-ansi-cjs": "npm:strip-ansi@^6.0.1",
|
|
||||||
"wrap-ansi": "^8.1.0",
|
|
||||||
"wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@one-ini/wasm": {
|
|
||||||
"version": "0.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@one-ini/wasm/-/wasm-0.1.1.tgz",
|
|
||||||
"integrity": "sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw=="
|
|
||||||
},
|
|
||||||
"node_modules/@pkgjs/parseargs": {
|
|
||||||
"version": "0.11.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
|
|
||||||
"integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
|
|
||||||
"optional": true,
|
|
||||||
"engines": {
|
|
||||||
"node": ">=14"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/abbrev": {
|
|
||||||
"version": "2.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz",
|
|
||||||
"integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==",
|
|
||||||
"engines": {
|
|
||||||
"node": "^14.17.0 || ^16.13.0 || >=18.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/ansi-regex": {
|
|
||||||
"version": "6.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
|
|
||||||
"integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/chalk/ansi-regex?sponsor=1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/ansi-styles": {
|
|
||||||
"version": "6.2.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
|
|
||||||
"integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/balanced-match": {
|
|
||||||
"version": "1.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
|
||||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
|
|
||||||
},
|
|
||||||
"node_modules/brace-expansion": {
|
|
||||||
"version": "2.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
|
||||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
|
||||||
"dependencies": {
|
|
||||||
"balanced-match": "^1.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/color-convert": {
|
|
||||||
"version": "2.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
|
||||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
|
||||||
"dependencies": {
|
|
||||||
"color-name": "~1.1.4"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=7.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/color-name": {
|
|
||||||
"version": "1.1.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
|
||||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
|
|
||||||
},
|
|
||||||
"node_modules/commander": {
|
|
||||||
"version": "10.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz",
|
|
||||||
"integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=14"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/config-chain": {
|
|
||||||
"version": "1.1.13",
|
|
||||||
"resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz",
|
|
||||||
"integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==",
|
|
||||||
"dependencies": {
|
|
||||||
"ini": "^1.3.4",
|
|
||||||
"proto-list": "~1.2.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/cross-spawn": {
|
|
||||||
"version": "7.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
|
||||||
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
|
|
||||||
"dependencies": {
|
|
||||||
"path-key": "^3.1.0",
|
|
||||||
"shebang-command": "^2.0.0",
|
|
||||||
"which": "^2.0.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/eastasianwidth": {
|
|
||||||
"version": "0.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
|
|
||||||
"integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="
|
|
||||||
},
|
|
||||||
"node_modules/editorconfig": {
|
|
||||||
"version": "1.0.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-1.0.4.tgz",
|
|
||||||
"integrity": "sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==",
|
|
||||||
"dependencies": {
|
|
||||||
"@one-ini/wasm": "0.1.1",
|
|
||||||
"commander": "^10.0.0",
|
|
||||||
"minimatch": "9.0.1",
|
|
||||||
"semver": "^7.5.3"
|
|
||||||
},
|
|
||||||
"bin": {
|
|
||||||
"editorconfig": "bin/editorconfig"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=14"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/emoji-regex": {
|
|
||||||
"version": "9.2.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
|
|
||||||
"integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="
|
|
||||||
},
|
|
||||||
"node_modules/foreground-child": {
|
|
||||||
"version": "3.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz",
|
|
||||||
"integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==",
|
|
||||||
"dependencies": {
|
|
||||||
"cross-spawn": "^7.0.0",
|
|
||||||
"signal-exit": "^4.0.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=14"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/isaacs"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/glob": {
|
|
||||||
"version": "10.3.10",
|
|
||||||
"resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz",
|
|
||||||
"integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==",
|
|
||||||
"dependencies": {
|
|
||||||
"foreground-child": "^3.1.0",
|
|
||||||
"jackspeak": "^2.3.5",
|
|
||||||
"minimatch": "^9.0.1",
|
|
||||||
"minipass": "^5.0.0 || ^6.0.2 || ^7.0.0",
|
|
||||||
"path-scurry": "^1.10.1"
|
|
||||||
},
|
|
||||||
"bin": {
|
|
||||||
"glob": "dist/esm/bin.mjs"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=16 || 14 >=14.17"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/isaacs"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/ini": {
|
|
||||||
"version": "1.3.8",
|
|
||||||
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
|
|
||||||
"integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="
|
|
||||||
},
|
|
||||||
"node_modules/is-fullwidth-code-point": {
|
|
||||||
"version": "3.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
|
||||||
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/isexe": {
|
|
||||||
"version": "2.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
|
|
||||||
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="
|
|
||||||
},
|
|
||||||
"node_modules/jackspeak": {
|
|
||||||
"version": "2.3.6",
|
|
||||||
"resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz",
|
|
||||||
"integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==",
|
|
||||||
"dependencies": {
|
|
||||||
"@isaacs/cliui": "^8.0.2"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=14"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/isaacs"
|
|
||||||
},
|
|
||||||
"optionalDependencies": {
|
|
||||||
"@pkgjs/parseargs": "^0.11.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/js-beautify": {
|
|
||||||
"version": "1.14.11",
|
|
||||||
"resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.14.11.tgz",
|
|
||||||
"integrity": "sha512-rPogWqAfoYh1Ryqqh2agUpVfbxAhbjuN1SmU86dskQUKouRiggUTCO4+2ym9UPXllc2WAp0J+T5qxn7Um3lCdw==",
|
|
||||||
"dependencies": {
|
|
||||||
"config-chain": "^1.1.13",
|
|
||||||
"editorconfig": "^1.0.3",
|
|
||||||
"glob": "^10.3.3",
|
|
||||||
"nopt": "^7.2.0"
|
|
||||||
},
|
|
||||||
"bin": {
|
|
||||||
"css-beautify": "js/bin/css-beautify.js",
|
|
||||||
"html-beautify": "js/bin/html-beautify.js",
|
|
||||||
"js-beautify": "js/bin/js-beautify.js"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=14"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/lru-cache": {
|
|
||||||
"version": "10.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz",
|
|
||||||
"integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==",
|
|
||||||
"engines": {
|
|
||||||
"node": "14 || >=16.14"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/minimatch": {
|
|
||||||
"version": "9.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.1.tgz",
|
|
||||||
"integrity": "sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==",
|
|
||||||
"dependencies": {
|
|
||||||
"brace-expansion": "^2.0.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=16 || 14 >=14.17"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/isaacs"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/minipass": {
|
|
||||||
"version": "7.0.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz",
|
|
||||||
"integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=16 || 14 >=14.17"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/nopt": {
|
|
||||||
"version": "7.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.0.tgz",
|
|
||||||
"integrity": "sha512-CVDtwCdhYIvnAzFoJ6NJ6dX3oga9/HyciQDnG1vQDjSLMeKLJ4A93ZqYKDrgYSr1FBY5/hMYC+2VCi24pgpkGA==",
|
|
||||||
"dependencies": {
|
|
||||||
"abbrev": "^2.0.0"
|
|
||||||
},
|
|
||||||
"bin": {
|
|
||||||
"nopt": "bin/nopt.js"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": "^14.17.0 || ^16.13.0 || >=18.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/path-key": {
|
|
||||||
"version": "3.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
|
|
||||||
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/path-scurry": {
|
|
||||||
"version": "1.10.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz",
|
|
||||||
"integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==",
|
|
||||||
"dependencies": {
|
|
||||||
"lru-cache": "^9.1.1 || ^10.0.0",
|
|
||||||
"minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=16 || 14 >=14.17"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/isaacs"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/proto-list": {
|
|
||||||
"version": "1.2.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz",
|
|
||||||
"integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA=="
|
|
||||||
},
|
|
||||||
"node_modules/semver": {
|
|
||||||
"version": "7.5.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
|
|
||||||
"integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
|
|
||||||
"dependencies": {
|
|
||||||
"lru-cache": "^6.0.0"
|
|
||||||
},
|
|
||||||
"bin": {
|
|
||||||
"semver": "bin/semver.js"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/semver/node_modules/lru-cache": {
|
|
||||||
"version": "6.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
|
||||||
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
|
||||||
"dependencies": {
|
|
||||||
"yallist": "^4.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/shebang-command": {
|
|
||||||
"version": "2.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
|
||||||
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
|
|
||||||
"dependencies": {
|
|
||||||
"shebang-regex": "^3.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/shebang-regex": {
|
|
||||||
"version": "3.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
|
|
||||||
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/signal-exit": {
|
|
||||||
"version": "4.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
|
|
||||||
"integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=14"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/isaacs"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/string-width": {
|
|
||||||
"version": "5.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
|
|
||||||
"integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
|
|
||||||
"dependencies": {
|
|
||||||
"eastasianwidth": "^0.2.0",
|
|
||||||
"emoji-regex": "^9.2.2",
|
|
||||||
"strip-ansi": "^7.0.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/string-width-cjs": {
|
|
||||||
"name": "string-width",
|
|
||||||
"version": "4.2.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
|
||||||
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
|
|
||||||
"dependencies": {
|
|
||||||
"emoji-regex": "^8.0.0",
|
|
||||||
"is-fullwidth-code-point": "^3.0.0",
|
|
||||||
"strip-ansi": "^6.0.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/string-width-cjs/node_modules/ansi-regex": {
|
|
||||||
"version": "5.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
|
||||||
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/string-width-cjs/node_modules/emoji-regex": {
|
|
||||||
"version": "8.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
|
||||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
|
|
||||||
},
|
|
||||||
"node_modules/string-width-cjs/node_modules/strip-ansi": {
|
|
||||||
"version": "6.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
|
||||||
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
|
||||||
"dependencies": {
|
|
||||||
"ansi-regex": "^5.0.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/strip-ansi": {
|
|
||||||
"version": "7.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
|
|
||||||
"integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
|
|
||||||
"dependencies": {
|
|
||||||
"ansi-regex": "^6.0.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/chalk/strip-ansi?sponsor=1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/strip-ansi-cjs": {
|
|
||||||
"name": "strip-ansi",
|
|
||||||
"version": "6.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
|
||||||
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
|
||||||
"dependencies": {
|
|
||||||
"ansi-regex": "^5.0.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/strip-ansi-cjs/node_modules/ansi-regex": {
|
|
||||||
"version": "5.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
|
||||||
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/which": {
|
|
||||||
"version": "2.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
|
||||||
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
|
|
||||||
"dependencies": {
|
|
||||||
"isexe": "^2.0.0"
|
|
||||||
},
|
|
||||||
"bin": {
|
|
||||||
"node-which": "bin/node-which"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/wrap-ansi": {
|
|
||||||
"version": "8.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
|
|
||||||
"integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
|
|
||||||
"dependencies": {
|
|
||||||
"ansi-styles": "^6.1.0",
|
|
||||||
"string-width": "^5.0.1",
|
|
||||||
"strip-ansi": "^7.0.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/wrap-ansi-cjs": {
|
|
||||||
"name": "wrap-ansi",
|
|
||||||
"version": "7.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
|
||||||
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
|
|
||||||
"dependencies": {
|
|
||||||
"ansi-styles": "^4.0.0",
|
|
||||||
"string-width": "^4.1.0",
|
|
||||||
"strip-ansi": "^6.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/wrap-ansi-cjs/node_modules/ansi-regex": {
|
|
||||||
"version": "5.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
|
||||||
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/wrap-ansi-cjs/node_modules/ansi-styles": {
|
|
||||||
"version": "4.3.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
|
||||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
|
||||||
"dependencies": {
|
|
||||||
"color-convert": "^2.0.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=8"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/wrap-ansi-cjs/node_modules/emoji-regex": {
|
|
||||||
"version": "8.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
|
||||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
|
|
||||||
},
|
|
||||||
"node_modules/wrap-ansi-cjs/node_modules/string-width": {
|
|
||||||
"version": "4.2.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
|
||||||
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
|
|
||||||
"dependencies": {
|
|
||||||
"emoji-regex": "^8.0.0",
|
|
||||||
"is-fullwidth-code-point": "^3.0.0",
|
|
||||||
"strip-ansi": "^6.0.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/wrap-ansi-cjs/node_modules/strip-ansi": {
|
|
||||||
"version": "6.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
|
||||||
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
|
||||||
"dependencies": {
|
|
||||||
"ansi-regex": "^5.0.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/yallist": {
|
|
||||||
"version": "4.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
|
||||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"@isaacs/cliui": {
|
|
||||||
"version": "8.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
|
|
||||||
"integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
|
|
||||||
"requires": {
|
|
||||||
"string-width": "^5.1.2",
|
|
||||||
"string-width-cjs": "npm:string-width@^4.2.0",
|
|
||||||
"strip-ansi": "^7.0.1",
|
|
||||||
"strip-ansi-cjs": "npm:strip-ansi@^6.0.1",
|
|
||||||
"wrap-ansi": "^8.1.0",
|
|
||||||
"wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"@one-ini/wasm": {
|
|
||||||
"version": "0.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@one-ini/wasm/-/wasm-0.1.1.tgz",
|
|
||||||
"integrity": "sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw=="
|
|
||||||
},
|
|
||||||
"@pkgjs/parseargs": {
|
|
||||||
"version": "0.11.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
|
|
||||||
"integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"abbrev": {
|
|
||||||
"version": "2.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz",
|
|
||||||
"integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ=="
|
|
||||||
},
|
|
||||||
"ansi-regex": {
|
|
||||||
"version": "6.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
|
|
||||||
"integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA=="
|
|
||||||
},
|
|
||||||
"ansi-styles": {
|
|
||||||
"version": "6.2.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
|
|
||||||
"integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug=="
|
|
||||||
},
|
|
||||||
"balanced-match": {
|
|
||||||
"version": "1.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
|
||||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
|
|
||||||
},
|
|
||||||
"brace-expansion": {
|
|
||||||
"version": "2.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
|
||||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
|
||||||
"requires": {
|
|
||||||
"balanced-match": "^1.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"color-convert": {
|
|
||||||
"version": "2.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
|
||||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
|
||||||
"requires": {
|
|
||||||
"color-name": "~1.1.4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"color-name": {
|
|
||||||
"version": "1.1.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
|
||||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
|
|
||||||
},
|
|
||||||
"commander": {
|
|
||||||
"version": "10.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz",
|
|
||||||
"integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug=="
|
|
||||||
},
|
|
||||||
"config-chain": {
|
|
||||||
"version": "1.1.13",
|
|
||||||
"resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz",
|
|
||||||
"integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==",
|
|
||||||
"requires": {
|
|
||||||
"ini": "^1.3.4",
|
|
||||||
"proto-list": "~1.2.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"cross-spawn": {
|
|
||||||
"version": "7.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
|
||||||
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
|
|
||||||
"requires": {
|
|
||||||
"path-key": "^3.1.0",
|
|
||||||
"shebang-command": "^2.0.0",
|
|
||||||
"which": "^2.0.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"eastasianwidth": {
|
|
||||||
"version": "0.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
|
|
||||||
"integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="
|
|
||||||
},
|
|
||||||
"editorconfig": {
|
|
||||||
"version": "1.0.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-1.0.4.tgz",
|
|
||||||
"integrity": "sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==",
|
|
||||||
"requires": {
|
|
||||||
"@one-ini/wasm": "0.1.1",
|
|
||||||
"commander": "^10.0.0",
|
|
||||||
"minimatch": "9.0.1",
|
|
||||||
"semver": "^7.5.3"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"emoji-regex": {
|
|
||||||
"version": "9.2.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
|
|
||||||
"integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="
|
|
||||||
},
|
|
||||||
"foreground-child": {
|
|
||||||
"version": "3.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz",
|
|
||||||
"integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==",
|
|
||||||
"requires": {
|
|
||||||
"cross-spawn": "^7.0.0",
|
|
||||||
"signal-exit": "^4.0.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"glob": {
|
|
||||||
"version": "10.3.10",
|
|
||||||
"resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz",
|
|
||||||
"integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==",
|
|
||||||
"requires": {
|
|
||||||
"foreground-child": "^3.1.0",
|
|
||||||
"jackspeak": "^2.3.5",
|
|
||||||
"minimatch": "^9.0.1",
|
|
||||||
"minipass": "^5.0.0 || ^6.0.2 || ^7.0.0",
|
|
||||||
"path-scurry": "^1.10.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ini": {
|
|
||||||
"version": "1.3.8",
|
|
||||||
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
|
|
||||||
"integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="
|
|
||||||
},
|
|
||||||
"is-fullwidth-code-point": {
|
|
||||||
"version": "3.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
|
||||||
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
|
|
||||||
},
|
|
||||||
"isexe": {
|
|
||||||
"version": "2.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
|
|
||||||
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="
|
|
||||||
},
|
|
||||||
"jackspeak": {
|
|
||||||
"version": "2.3.6",
|
|
||||||
"resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz",
|
|
||||||
"integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==",
|
|
||||||
"requires": {
|
|
||||||
"@isaacs/cliui": "^8.0.2",
|
|
||||||
"@pkgjs/parseargs": "^0.11.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"js-beautify": {
|
|
||||||
"version": "1.14.11",
|
|
||||||
"resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.14.11.tgz",
|
|
||||||
"integrity": "sha512-rPogWqAfoYh1Ryqqh2agUpVfbxAhbjuN1SmU86dskQUKouRiggUTCO4+2ym9UPXllc2WAp0J+T5qxn7Um3lCdw==",
|
|
||||||
"requires": {
|
|
||||||
"config-chain": "^1.1.13",
|
|
||||||
"editorconfig": "^1.0.3",
|
|
||||||
"glob": "^10.3.3",
|
|
||||||
"nopt": "^7.2.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"lru-cache": {
|
|
||||||
"version": "10.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz",
|
|
||||||
"integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q=="
|
|
||||||
},
|
|
||||||
"minimatch": {
|
|
||||||
"version": "9.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.1.tgz",
|
|
||||||
"integrity": "sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==",
|
|
||||||
"requires": {
|
|
||||||
"brace-expansion": "^2.0.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"minipass": {
|
|
||||||
"version": "7.0.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz",
|
|
||||||
"integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ=="
|
|
||||||
},
|
|
||||||
"nopt": {
|
|
||||||
"version": "7.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.0.tgz",
|
|
||||||
"integrity": "sha512-CVDtwCdhYIvnAzFoJ6NJ6dX3oga9/HyciQDnG1vQDjSLMeKLJ4A93ZqYKDrgYSr1FBY5/hMYC+2VCi24pgpkGA==",
|
|
||||||
"requires": {
|
|
||||||
"abbrev": "^2.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"path-key": {
|
|
||||||
"version": "3.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
|
|
||||||
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="
|
|
||||||
},
|
|
||||||
"path-scurry": {
|
|
||||||
"version": "1.10.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz",
|
|
||||||
"integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==",
|
|
||||||
"requires": {
|
|
||||||
"lru-cache": "^9.1.1 || ^10.0.0",
|
|
||||||
"minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"proto-list": {
|
|
||||||
"version": "1.2.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz",
|
|
||||||
"integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA=="
|
|
||||||
},
|
|
||||||
"semver": {
|
|
||||||
"version": "7.5.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
|
|
||||||
"integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
|
|
||||||
"requires": {
|
|
||||||
"lru-cache": "^6.0.0"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"lru-cache": {
|
|
||||||
"version": "6.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
|
||||||
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
|
||||||
"requires": {
|
|
||||||
"yallist": "^4.0.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"shebang-command": {
|
|
||||||
"version": "2.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
|
||||||
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
|
|
||||||
"requires": {
|
|
||||||
"shebang-regex": "^3.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"shebang-regex": {
|
|
||||||
"version": "3.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
|
|
||||||
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="
|
|
||||||
},
|
|
||||||
"signal-exit": {
|
|
||||||
"version": "4.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
|
|
||||||
"integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="
|
|
||||||
},
|
|
||||||
"string-width": {
|
|
||||||
"version": "5.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
|
|
||||||
"integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
|
|
||||||
"requires": {
|
|
||||||
"eastasianwidth": "^0.2.0",
|
|
||||||
"emoji-regex": "^9.2.2",
|
|
||||||
"strip-ansi": "^7.0.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"string-width-cjs": {
|
|
||||||
"version": "npm:string-width@4.2.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
|
||||||
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
|
|
||||||
"requires": {
|
|
||||||
"emoji-regex": "^8.0.0",
|
|
||||||
"is-fullwidth-code-point": "^3.0.0",
|
|
||||||
"strip-ansi": "^6.0.1"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"ansi-regex": {
|
|
||||||
"version": "5.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
|
||||||
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
|
|
||||||
},
|
|
||||||
"emoji-regex": {
|
|
||||||
"version": "8.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
|
||||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
|
|
||||||
},
|
|
||||||
"strip-ansi": {
|
|
||||||
"version": "6.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
|
||||||
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
|
||||||
"requires": {
|
|
||||||
"ansi-regex": "^5.0.1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"strip-ansi": {
|
|
||||||
"version": "7.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
|
|
||||||
"integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
|
|
||||||
"requires": {
|
|
||||||
"ansi-regex": "^6.0.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"strip-ansi-cjs": {
|
|
||||||
"version": "npm:strip-ansi@6.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
|
||||||
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
|
||||||
"requires": {
|
|
||||||
"ansi-regex": "^5.0.1"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"ansi-regex": {
|
|
||||||
"version": "5.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
|
||||||
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"which": {
|
|
||||||
"version": "2.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
|
||||||
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
|
|
||||||
"requires": {
|
|
||||||
"isexe": "^2.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"wrap-ansi": {
|
|
||||||
"version": "8.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
|
|
||||||
"integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
|
|
||||||
"requires": {
|
|
||||||
"ansi-styles": "^6.1.0",
|
|
||||||
"string-width": "^5.0.1",
|
|
||||||
"strip-ansi": "^7.0.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"wrap-ansi-cjs": {
|
|
||||||
"version": "npm:wrap-ansi@7.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
|
||||||
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
|
|
||||||
"requires": {
|
|
||||||
"ansi-styles": "^4.0.0",
|
|
||||||
"string-width": "^4.1.0",
|
|
||||||
"strip-ansi": "^6.0.0"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"ansi-regex": {
|
|
||||||
"version": "5.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
|
||||||
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
|
|
||||||
},
|
|
||||||
"ansi-styles": {
|
|
||||||
"version": "4.3.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
|
||||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
|
||||||
"requires": {
|
|
||||||
"color-convert": "^2.0.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"emoji-regex": {
|
|
||||||
"version": "8.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
|
||||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
|
|
||||||
},
|
|
||||||
"string-width": {
|
|
||||||
"version": "4.2.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
|
||||||
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
|
|
||||||
"requires": {
|
|
||||||
"emoji-regex": "^8.0.0",
|
|
||||||
"is-fullwidth-code-point": "^3.0.0",
|
|
||||||
"strip-ansi": "^6.0.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"strip-ansi": {
|
|
||||||
"version": "6.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
|
||||||
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
|
||||||
"requires": {
|
|
||||||
"ansi-regex": "^5.0.1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"yallist": {
|
|
||||||
"version": "4.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
|
||||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
23
package.json
|
@ -1,23 +0,0 @@
|
||||||
{
|
|
||||||
"name": "fxclient",
|
|
||||||
"version": "0.5.3",
|
|
||||||
"description": "A modded territorial.io client",
|
|
||||||
"main": "index.js",
|
|
||||||
"scripts": {
|
|
||||||
"build": "node index.js",
|
|
||||||
"build-only": "node build.js"
|
|
||||||
},
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "git+https://github.com/fxclient/FXclient.git"
|
|
||||||
},
|
|
||||||
"author": "",
|
|
||||||
"license": "ISC",
|
|
||||||
"bugs": {
|
|
||||||
"url": "https://github.com/fxclient/FXclient/issues"
|
|
||||||
},
|
|
||||||
"homepage": "https://github.com/fxclient/FXclient#readme",
|
|
||||||
"dependencies": {
|
|
||||||
"js-beautify": "^1.14.11"
|
|
||||||
}
|
|
||||||
}
|
|
55
readme.md
|
@ -1,55 +0,0 @@
|
||||||
<p align="center">
|
|
||||||
<a href="https://fxclient.github.io/FXclient/">
|
|
||||||
<picture>
|
|
||||||
<source media="(prefers-color-scheme: dark)" srcset="/assets/logo_text_dark.png">
|
|
||||||
<source media="(prefers-color-scheme: light)" srcset="/assets/logo_text_light.png">
|
|
||||||
<img src="/assets/logo_text_light.png" width="20%">
|
|
||||||
</picture>
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
<p align="center">
|
|
||||||
<a href="https://discord.gg/JEwYWGraj7"><img alt="FX Client Discord" src="https://img.shields.io/discord/1055801912286515220?logo=discord&logoColor=white&label=FX%20Client&color=5865F2"></a>
|
|
||||||
<a href="https://github.com/fxclient/FXclient/actions/workflows/deploy_github_pages.yml"><img src="https://github.com/fxclient/FXclient/actions/workflows/deploy_github_pages.yml/badge.svg" alt="Build and Publish to GitHub Pages"></a>
|
|
||||||
<a href="https://fxclient.github.io/FXclient/"><img src="https://github.com/fxclient/FXclient/actions/workflows/pages/pages-build-deployment/badge.svg" alt="pages-build-deployment"></a>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
## What is FX Client?
|
|
||||||
FX Client is the first Territorial.io client, targeting better User Interface and better User Experience, It's basically Territorial.io but better.
|
|
||||||
|
|
||||||
**You can use the latest version of the client here: https://fxclient.github.io/FXclient/**
|
|
||||||
|
|
||||||
## Features:
|
|
||||||
1. It's 100% free and open source on Github
|
|
||||||
2. It's ad-free and removes game's default ads.
|
|
||||||
3. It makes game look cooler, by replacing default assets with new ones.
|
|
||||||
4. Displays your troop density and maximum troops
|
|
||||||
5. Displays the density of players and bots
|
|
||||||
6. Adds a "Clan" tab on the leaderboard, allowing you to easily see your clanmates
|
|
||||||
7. Hovering tooltip: makes the territory map information (normally visible on right click) be visible constantly (on hover)
|
|
||||||
8. Adds a player list
|
|
||||||
9. Adds the ability to view the history of who donated to a player during a team game by clicking on their name in the leaderboard or the player list
|
|
||||||
10. Adds a win counter
|
|
||||||
11. Can be installed as a PWA (progressive web app) ensuring maximum enjoyment on consoles, phones and even desktop devices
|
|
||||||
|
|
||||||
#### The client has a settings menu, from which you can:
|
|
||||||
|
|
||||||
12. Make fullscreen mode trigger automatically
|
|
||||||
13. Set a custom main menu background
|
|
||||||
14. Create custom attack percentage keybinds
|
|
||||||
|
|
||||||
## Building Locally
|
|
||||||
|
|
||||||
To build the client locally, install Node.js if you haven't already, clone the repo, then run:
|
|
||||||
|
|
||||||
```
|
|
||||||
npm install
|
|
||||||
npm run build
|
|
||||||
```
|
|
||||||
|
|
||||||
This will install the dependencies, download the game and build the client.
|
|
||||||
|
|
||||||
To build from an already downloaded copy of the game, use `npm run build-only`.
|
|
||||||
|
|
||||||
## Contact Us
|
|
||||||
|
|
||||||
Join the FX Client Discord server: https://discord.gg/JEwYWGraj7
|
|
525
src/fx_core.js
|
@ -1,525 +0,0 @@
|
||||||
const fx_version = '0.6.4.1'; // FX Client Version
|
|
||||||
const fx_update = 'May 20'; // 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, """).replace(/'/g, "'");
|
|
||||||
}
|
|
||||||
|
|
||||||
function KeybindsInput(containerElement) {
|
|
||||||
const header = document.createElement("p");
|
|
||||||
header.innerText = "Attack Percentage Keybinds";
|
|
||||||
const keybindContainer = document.createElement("div");
|
|
||||||
keybindContainer.className = "arrayinput";
|
|
||||||
const keybindAddButton = document.createElement("button");
|
|
||||||
keybindAddButton.innerText = "Add";
|
|
||||||
containerElement.append(header, keybindContainer, keybindAddButton);
|
|
||||||
this.container = keybindContainer;
|
|
||||||
this.keys = [ "key", "type", "value" ];
|
|
||||||
this.objectArray = [];
|
|
||||||
this.addObject = function () {
|
|
||||||
this.objectArray.push({ key: "", type: "absolute", value: 0.8 });
|
|
||||||
this.displayObjects();
|
|
||||||
keybindAddButton.scrollIntoView(false);
|
|
||||||
};
|
|
||||||
this.update = function () {
|
|
||||||
this.objectArray = settings.attackPercentageKeybinds;
|
|
||||||
this.displayObjects();
|
|
||||||
}
|
|
||||||
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 = '<option value="absolute">Absolute</option><option value="relative">Relative</option>';
|
|
||||||
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"
|
|
||||||
const isAbsolute = this.objectArray[i].type === "absolute";
|
|
||||||
inputField.type = isAbsolute ? "text" : "number";
|
|
||||||
if (isAbsolute) inputField.addEventListener("click", this.convertIntoNumberInput.bind(this, i, key), { once: true });
|
|
||||||
else inputField.setAttribute("step", "0.1");
|
|
||||||
inputField.addEventListener("input", this.updateObject.bind(this, i, key));
|
|
||||||
}
|
|
||||||
if (key === "value" && this.objectArray[i].type === "absolute")
|
|
||||||
inputField.value = this.objectArray[i][key] * 100 + "%";
|
|
||||||
else 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 });
|
|
||||||
};
|
|
||||||
/** @param {PointerEvent} event */
|
|
||||||
this.convertIntoNumberInput = function (index, property, event) {
|
|
||||||
event.target.value = event.target.value.slice(0, -1);
|
|
||||||
event.target.type = "number";
|
|
||||||
event.target.addEventListener("blur", () => {
|
|
||||||
//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" ? (
|
|
||||||
this.objectArray[index].type === "absolute" ? parseFloat(event.target.value) / 100 : 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,
|
|
||||||
"hoveringTooltip": true,
|
|
||||||
//"hideAllLinks": false,
|
|
||||||
"realisticNames": false,
|
|
||||||
"showPlayerDensity": true,
|
|
||||||
"coloredDensity": true,
|
|
||||||
"densityDisplayStyle": "percentage",
|
|
||||||
//"customMapFileBtn": true
|
|
||||||
"customBackgroundUrl": "",
|
|
||||||
"attackPercentageKeybinds": [],
|
|
||||||
};
|
|
||||||
const discontinuedSettings = [ "hideAllLinks", "fontName" ];
|
|
||||||
let makeMainMenuTransparent = false;
|
|
||||||
var settingsManager = new (function() {
|
|
||||||
const settingsStructure = [
|
|
||||||
//{ for: "fontName", type: "textInput", label: "Font name:", placeholder: "Enter font name", tooltip: "Name of the font to be used for rendering. For example: Arial, Georgia, sans-serif, serif, Comic Sans MS, ..."},
|
|
||||||
{ type: "button", text: "Reset Wins Counter", action: removeWins },
|
|
||||||
{ for: "displayWinCounter", type: "checkbox", label: "Display win counter",
|
|
||||||
note: "The win counter tracks multiplayer solo wins (not in team games)" },
|
|
||||||
{ for: "useFullscreenMode", type: "checkbox", label: "Use fullscreen mode",
|
|
||||||
note: "Note: fullscreen mode will trigger after you click anywhere on the page due to browser policy restrictions." },
|
|
||||||
{ for: "hoveringTooltip", type: "checkbox", label: "Hovering tooltip",
|
|
||||||
note: "Display map territory info constantly (on mouse hover) instead of only when right clicking on the map" },
|
|
||||||
//{ for: "hideAllLinks", type: "checkbox", label: "Hide Links option also hides app store links" },
|
|
||||||
{ for: "realisticNames", type: "checkbox", label: "Realistic Bot Names" },
|
|
||||||
{ for: "showPlayerDensity", type: "checkbox", label: "Show player density" },
|
|
||||||
{ for: "coloredDensity", type: "checkbox", label: "Colored density", note: "Display the density with a color between red and green depending on the density value" },
|
|
||||||
{ for: "densityDisplayStyle", type: "selectMenu", label: "Density value display style:", tooltip: "Controls how the territorial density value should be rendered", options: [
|
|
||||||
{ value: "percentage", label: "Percentage" },
|
|
||||||
{ value: "absoluteQuotient", label: "Value from 0 to 150 (BetterTT style)" }
|
|
||||||
]},
|
|
||||||
{ for: "customBackgroundUrl", type: "textInput", label: "Custom main menu background:", placeholder: "Enter an image URL here", tooltip: "A custom image to be shown as the main menu background instead of the currently selected map." },
|
|
||||||
KeybindsInput
|
|
||||||
];
|
|
||||||
const settingsContainer = document.querySelector(".settings .scrollable");
|
|
||||||
var inputFields = {}; // (includes select menus)
|
|
||||||
var checkboxFields = {};
|
|
||||||
var customElements = [];
|
|
||||||
settingsStructure.forEach(item => {
|
|
||||||
if (typeof item === "function") {
|
|
||||||
const container = document.createElement("div");
|
|
||||||
customElements.push(new item(container));
|
|
||||||
return settingsContainer.append(container);
|
|
||||||
}
|
|
||||||
const label = document.createElement("label");
|
|
||||||
if (item.tooltip) label.title = item.tooltip;
|
|
||||||
const isValueInput = item.type.endsWith("Input");
|
|
||||||
const element = document.createElement(isValueInput || item.type === "checkbox" ? "input" : item.type === "selectMenu" ? "select" : "button");
|
|
||||||
if (item.type === "textInput") element.type = "text";
|
|
||||||
if (item.placeholder) element.placeholder = item.placeholder;
|
|
||||||
if (isValueInput || item.type === "selectMenu") inputFields[item.for] = element;
|
|
||||||
if (item.text) element.innerText = item.text;
|
|
||||||
if (item.action) element.addEventListener("click", item.action);
|
|
||||||
if (item.label) label.append(item.label + " ");
|
|
||||||
if (item.note) {
|
|
||||||
const note = document.createElement("small");
|
|
||||||
note.innerText = item.note;
|
|
||||||
label.append(document.createElement("br"), note)
|
|
||||||
}
|
|
||||||
if (item.options) item.options.forEach(option => {
|
|
||||||
const optionElement = document.createElement("option");
|
|
||||||
optionElement.setAttribute("value", option.value);
|
|
||||||
optionElement.innerText = option.label;
|
|
||||||
element.append(optionElement);
|
|
||||||
});
|
|
||||||
label.append(element);
|
|
||||||
if (item.type === "checkbox") {
|
|
||||||
element.type = "checkbox";
|
|
||||||
const checkmark = document.createElement("span");
|
|
||||||
checkmark.className = "checkmark";
|
|
||||||
label.className = "checkbox";
|
|
||||||
label.append(checkmark);
|
|
||||||
checkboxFields[item.for] = element;
|
|
||||||
} else label.append(document.createElement("br"));
|
|
||||||
settingsContainer.append(label, document.createElement("br"));
|
|
||||||
});
|
|
||||||
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");
|
|
||||||
discontinuedSettings.forEach(settingName => delete settings[settingName]);
|
|
||||||
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();
|
|
||||||
};
|
|
||||||
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]; });
|
|
||||||
customElements.forEach(element => element.update());
|
|
||||||
};
|
|
||||||
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 = `<h3>Players (${gHumans})</h3>`;
|
|
||||||
for (let i = 0; i < gLobbyMaxJoin; i++) {
|
|
||||||
if (i === gHumans) listContent += `<h3>Bots (${gLobbyMaxJoin - gHumans})</h3>`;
|
|
||||||
listContent += `<tr data-player-id="${i}"><td><span class="color-light-gray">${i + 1}.</span> ${escapeHtml(playerNames[i])}</td></tr>`
|
|
||||||
}
|
|
||||||
document.getElementById("playerlist_content").innerHTML = listContent;
|
|
||||||
document.getElementById("playerlist_content").setAttribute("class", getVar("gIsTeamGame") ? "clickable" : "");
|
|
||||||
WindowManager.openWindow("playerList");
|
|
||||||
}
|
|
||||||
this.hoveringOverButton = false;
|
|
||||||
this.drawButton = (canvas, x, y, size) => {
|
|
||||||
canvas.fillRect(x, y, size, size);
|
|
||||||
canvas.fillStyle = this.hoveringOverButton ? "#aaaaaaaa" : "#000000aa";
|
|
||||||
canvas.clearRect(x + 1, y + 1, size - 2, size - 2);
|
|
||||||
canvas.fillRect(x + 1, y + 1, size - 2, size - 2);
|
|
||||||
canvas.fillStyle = "#ffffff";
|
|
||||||
canvas.imageSmoothingEnabled = true;
|
|
||||||
canvas.drawImage(playersIcon, x + 2, y + 2, size - 4, size - 4);
|
|
||||||
canvas.imageSmoothingEnabled = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/** @param {string} name */
|
|
||||||
function parseClanFromPlayerName(name) {
|
|
||||||
const startIndex = name.indexOf("[");
|
|
||||||
// this is probably how the algorithm works, since a player with
|
|
||||||
// the name "][a]" will count as not being in a clan in the base game
|
|
||||||
return startIndex === -1 ? "" : name.slice(startIndex + 1, name.indexOf("]")).toUpperCase();
|
|
||||||
}
|
|
||||||
|
|
||||||
const leaderboardFilter = new (function() {
|
|
||||||
this.playersToInclude = [0,1,8,20,24,30,32,42,50,69,200,400,500,510,511]; // for testing
|
|
||||||
//this.playersToInclude = [];
|
|
||||||
this.tabLabels = ["ALL", "CLAN"];
|
|
||||||
// these get populated by the modified game code
|
|
||||||
this.filteredLeaderboard = [];
|
|
||||||
this.tabBarOffset = 0;
|
|
||||||
this.windowWidth = 0;
|
|
||||||
this.verticalClickThreshold = 1000;
|
|
||||||
this.hoveringOverTabs = false;
|
|
||||||
this.scrollToTop = () => {};
|
|
||||||
this.repaintLeaderboard = () => {};
|
|
||||||
|
|
||||||
this.selectedTab = 0;
|
|
||||||
this.tabHovering = -1;
|
|
||||||
//this.enabled = false;
|
|
||||||
this.enabled = true;
|
|
||||||
this.drawTabs = function(canvas, totalWidth, verticalOffset, colorForSelectedTab) {
|
|
||||||
canvas.textBaseline = "middle";
|
|
||||||
canvas.textAlign = "center";
|
|
||||||
const tabWidth = totalWidth / this.tabLabels.length;
|
|
||||||
const textOffsetY = verticalOffset + this.tabBarOffset / 2;
|
|
||||||
//console.log(verticalOffset, this.tabBarOffset, textOffsetY);
|
|
||||||
this.tabLabels.forEach((label, index) => {
|
|
||||||
if (index !== 0) canvas.fillRect(tabWidth * index, verticalOffset, 1, this.tabBarOffset);
|
|
||||||
if (this.selectedTab === index) {
|
|
||||||
canvas.fillStyle = colorForSelectedTab;
|
|
||||||
canvas.fillRect(tabWidth * index, verticalOffset, tabWidth, this.tabBarOffset);
|
|
||||||
canvas.fillStyle = "rgb(255,255,255)";
|
|
||||||
}
|
|
||||||
if (this.tabHovering === index) {
|
|
||||||
canvas.fillStyle = "rgba(255,255,255,0.3)";
|
|
||||||
canvas.fillRect(tabWidth * index, verticalOffset, tabWidth, this.tabBarOffset);
|
|
||||||
canvas.fillStyle = "rgb(255,255,255)";
|
|
||||||
}
|
|
||||||
canvas.fillText(label, tabWidth * index + tabWidth / 2, textOffsetY);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
this.setHovering = (isHovering, xRelative) => {
|
|
||||||
let repaintNeeded = false;
|
|
||||||
if (isHovering) {
|
|
||||||
const tab = Math.floor(xRelative / (this.windowWidth / this.tabLabels.length));
|
|
||||||
if (this.tabHovering !== tab) {
|
|
||||||
this.tabHovering = tab;
|
|
||||||
repaintNeeded = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (isHovering !== this.hoveringOverTabs) {
|
|
||||||
this.hoveringOverTabs = isHovering;
|
|
||||||
if (isHovering === false) this.tabHovering = -1;
|
|
||||||
if (!isHovering) repaintNeeded = true;
|
|
||||||
}
|
|
||||||
if (repaintNeeded) this.repaintLeaderboard();
|
|
||||||
return isHovering;
|
|
||||||
}
|
|
||||||
this.handleMouseDown = (xRelative) => {
|
|
||||||
//console.log("click; x: ", xRelative);
|
|
||||||
if (this.tabHovering !== this.selectedTab) {
|
|
||||||
this.selectedTab = this.tabHovering;
|
|
||||||
if (this.selectedTab === 0) this.clearFilter();
|
|
||||||
else if (this.selectedTab === 1) this.filterByOwnClan();
|
|
||||||
this.repaintLeaderboard();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
this.filterByOwnClan = () => {
|
|
||||||
this.playersToInclude = [];
|
|
||||||
const ownClan = parseClanFromPlayerName(getVar("playerNames")[getVar("playerId")]);
|
|
||||||
getVar("playerNames").forEach((name, id) => {
|
|
||||||
if (parseClanFromPlayerName(name) === ownClan) this.playersToInclude.push(id);
|
|
||||||
});
|
|
||||||
this.enabled = true;
|
|
||||||
this.scrollToTop();
|
|
||||||
};
|
|
||||||
this.clearFilter = () => { this.enabled = false; }
|
|
||||||
this.reset = () => {
|
|
||||||
this.enabled = false;
|
|
||||||
this.selectedTab = 0;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const hoveringTooltip = new (function() {
|
|
||||||
this.display = () => {}; // this gets populated by the modified game script
|
|
||||||
this.canvasPixelScale = 1;
|
|
||||||
document.getElementById("canvasA").addEventListener("mousemove", e => {
|
|
||||||
if (!settings.hoveringTooltip || !getVar("gameState")) return;
|
|
||||||
try {
|
|
||||||
this.display(this.canvasPixelScale * e.clientX, this.canvasPixelScale * e.clientY);
|
|
||||||
} catch (e) { console.error(e) }
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
var donationsTracker = new (function(){
|
|
||||||
this.openedWindowPlayerID = null;
|
|
||||||
this.contentElement = document.querySelector("#donationhistory_content");
|
|
||||||
this.donationHistory = Array(512);
|
|
||||||
// fill the array with empty arrays with length of 3
|
|
||||||
//for (var i = 0; i < 512; i++) this.donationHistory.push([]); // not needed as .reset is called on game start
|
|
||||||
this.getHistoryOf = function(playerID) {
|
|
||||||
return this.donationHistory[playerID].toReversed();
|
|
||||||
}
|
|
||||||
this.reset = function() { for (var i = 0; i < 512; i++) this.donationHistory[i] = []; };
|
|
||||||
this.logDonation = function(senderID, receiverID, amount) {
|
|
||||||
const donationInfo = [senderID, receiverID, amount];
|
|
||||||
this.donationHistory[receiverID].push(donationInfo);
|
|
||||||
this.donationHistory[senderID].push(donationInfo);
|
|
||||||
if (this.openedWindowPlayerID === senderID || this.openedWindowPlayerID === receiverID) {
|
|
||||||
const indexOfNewItem = this.donationHistory[this.openedWindowPlayerID === senderID ? senderID : receiverID].length;
|
|
||||||
this.contentElement.prepend(generateTableRowItem(donationInfo, indexOfNewItem, this.openedWindowPlayerID, true));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
function generateTableRowItem(historyItem, index, playerID, isNew) {
|
|
||||||
const playerNames = getVar("playerNames");
|
|
||||||
const row = document.createElement("tr");
|
|
||||||
if (isNew) row.setAttribute("class", "new");
|
|
||||||
let content = `<td><span class="color-light-gray">${index}.</span> `;
|
|
||||||
if (playerID === historyItem[1])
|
|
||||||
content += `Received <span class="color-green">${historyItem[2]}</span> resources from ${escapeHtml(playerNames[historyItem[0]])}`;
|
|
||||||
else content += `Sent <span class="color-red">${historyItem[2]}</span> resources to ${escapeHtml(playerNames[historyItem[1]])}`;
|
|
||||||
content += "</td>";
|
|
||||||
row.innerHTML = content;
|
|
||||||
return row;
|
|
||||||
}
|
|
||||||
this.displayHistory = function displayDonationsHistory(playerID, playerNames = getVar("playerNames"), isSingleplayer = getVar("gIsSingleplayer")) {
|
|
||||||
var history = donationsTracker.getHistoryOf(playerID);
|
|
||||||
console.log("History for " + playerNames[playerID] + ":");
|
|
||||||
console.log(history);
|
|
||||||
document.querySelector("#donationhistory h1").innerHTML = "Donation history for " + escapeHtml(playerNames[playerID]);
|
|
||||||
this.contentElement.innerHTML = "";
|
|
||||||
if (history.length > 0) history.forEach((historyItem, index) => {
|
|
||||||
this.contentElement.appendChild(generateTableRowItem(historyItem, history.length - index, playerID));
|
|
||||||
});
|
|
||||||
else this.contentElement.innerText = "Nothing to display";
|
|
||||||
this.openedWindowPlayerID = playerID;
|
|
||||||
WindowManager.openWindow("donationHistory", isSingleplayer);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
var utils = new (function() {
|
|
||||||
this.getMaxTroops = function(playerTerritories, playerID) { return (playerTerritories[playerID]*150).toString(); };
|
|
||||||
this.getDensity = function(playerID, playerBalances = getVar("playerBalances"), playerTerritories = getVar("playerTerritories")) {
|
|
||||||
if (settings.densityDisplayStyle === "percentage") return (((playerBalances[playerID] / ((playerTerritories[playerID] === 0 ? 1 : playerTerritories[playerID]) * 150)) * 100).toFixed(1) + "%");
|
|
||||||
else return (playerBalances[playerID] / (playerTerritories[playerID] === 0 ? 1 : playerTerritories[playerID])).toFixed(1);
|
|
||||||
};
|
|
||||||
this.isPointInRectangle = function(x, y, rectangleStartX, rectangleStartY, width, height) {
|
|
||||||
return x >= rectangleStartX && x <= rectangleStartX + width && y >= rectangleStartY && y <= rectangleStartY + height;
|
|
||||||
};
|
|
||||||
/** @param {CanvasRenderingContext2D} canvas @param {string} text */
|
|
||||||
this.fillTextMultiline = function(canvas, text, x, y, maxWidth) {
|
|
||||||
const lineHeight = parseInt(canvas.font.split(" ").find(part => part.endsWith("px")).slice(0, -2));
|
|
||||||
text.split("\n").forEach((line, index) => canvas.fillText(line, x, y + index * lineHeight, maxWidth));
|
|
||||||
}
|
|
||||||
this.textStyleBasedOnDensity = function(playerID) {
|
|
||||||
const playerBalances = getVar("playerBalances"), playerTerritories = getVar("playerTerritories");
|
|
||||||
return `hsl(${playerBalances[playerID] / (playerTerritories[playerID] * 1.5)}, 100%, 50%, 1)`;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
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"))};
|
|
||||||
}
|
|
||||||
settingsManager.applySettings();
|
|
||||||
|
|
||||||
console.log('Successfully loaded FX Client');
|
|
|
@ -1,32 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>404 Not Found</title>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
background-color: #000;
|
|
||||||
color: #fff;
|
|
||||||
text-decoration: none;
|
|
||||||
text-align: center;
|
|
||||||
font-family: 'Courier New', Courier, monospace;
|
|
||||||
font-size: 30px;
|
|
||||||
}
|
|
||||||
a {
|
|
||||||
color: red;
|
|
||||||
text-decoration: none;
|
|
||||||
transition: 0.4s;
|
|
||||||
}
|
|
||||||
a:hover {
|
|
||||||
color: darkgreen;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<p>404, Not Found</p>
|
|
||||||
<a href="https://fxclient.cf"><p>Visit FXclient.cf</p></a>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,108 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<meta name="og:image" content="https://fxclient.github.io/FXclient/assets/logo.png" />
|
|
||||||
<meta property="og:image" content="https://fxclient.github.io/FXclient/assets/logo.png">
|
|
||||||
<link rel="shortcut icon" href="https://fxclient.github.io/FXclient/favicon.ico" type="image/x-icon">
|
|
||||||
<meta property="og:title" content="FX Client">
|
|
||||||
<meta name="description" content="FX Client Cookie Policy">
|
|
||||||
<title>FX Client - Cookie Policy</title>
|
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
text-align: center;
|
|
||||||
background-color: #fff;
|
|
||||||
color: #000;
|
|
||||||
font-size: 25px;
|
|
||||||
font-family: 'Gill Sans', 'Gill Sans MT', Calibri, 'Trebuchet MS', sans-serif;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
#dd {
|
|
||||||
text-align: center;
|
|
||||||
background-color: #fff;
|
|
||||||
color: #000;
|
|
||||||
font-size: 40px;
|
|
||||||
font-family: 'Gill Sans', 'Gill Sans MT', Calibri, 'Trebuchet MS', sans-serif;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
a {
|
|
||||||
text-decoration: none;
|
|
||||||
transition: 0.2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
color: red;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<span id="dd">Cookie Policy</span>
|
|
||||||
|
|
||||||
<p>Last Update: 29 March 2024</p>
|
|
||||||
|
|
||||||
|
|
||||||
<p>1. General Information
|
|
||||||
<br />
|
|
||||||
FX Client uses cookies to improve the user experience. You can find out more about cookies in the sections below.
|
|
||||||
|
|
||||||
You don't have to accept cookies in order to use FX Client. We recommend cookies as they will improve your gaming experience.
|
|
||||||
|
|
||||||
We also use Local Storage to store your win counts and settngs.
|
|
||||||
|
|
||||||
To understand how we use your information, you may also check out our privacy policy: <a href="https://fxclient.github.io/FXclient/privacy_policy">fxclient.github.io/FXclient/privacy_policy</a>
|
|
||||||
</p>
|
|
||||||
<hr />
|
|
||||||
<p>2. What is a cookie?
|
|
||||||
<br />
|
|
||||||
Cookies are small text files that are stored on your computer. For example, a cookie can be used to remember your username.
|
|
||||||
</p>
|
|
||||||
<hr />
|
|
||||||
<p>3. What is Local Storage?
|
|
||||||
<br />
|
|
||||||
Local Storage is a place where we can store some information like your settings. It is not accessible by FX Client servers and is private.
|
|
||||||
</p>
|
|
||||||
<hr />
|
|
||||||
<p>
|
|
||||||
4. What types of cookies do we use?
|
|
||||||
<br />
|
|
||||||
We use functionality cookies to store your preferences:
|
|
||||||
<br>
|
|
||||||
your username;
|
|
||||||
a boolean, indicating if your interface is magnified or not;
|
|
||||||
the password of your one-vs-one account;
|
|
||||||
the color of your country;
|
|
||||||
selected emojis;
|
|
||||||
<br>
|
|
||||||
Furthermore, we use a cookie that assigns a random number to your device.
|
|
||||||
<br />
|
|
||||||
</p>
|
|
||||||
<hr />
|
|
||||||
<p>
|
|
||||||
5. How do our servers handle cookies transmitted by users?
|
|
||||||
<br />
|
|
||||||
We do not store and process cookies on our servers. Cookies on the client side will be deleted after one year of inactivity. Cookies will not be shared with third parties.
|
|
||||||
</p>
|
|
||||||
<hr />
|
|
||||||
<p>
|
|
||||||
6. More information about cookies
|
|
||||||
<br />
|
|
||||||
If you want to know how to delete or manage cookies, the following links may be helpful:
|
|
||||||
<br />
|
|
||||||
Cookie settings in Chrome and Android: <a href="https://support.google.com/chrome/answer/95647">support.google.com/chrome/answer/95647</a>
|
|
||||||
<br />
|
|
||||||
Cookie settings in iOS: <a href="http://support.apple.com/kb/PH5042">support.apple.com/kb/PH5042</a>
|
|
||||||
<br />
|
|
||||||
If you need more information about cookies, you may check out this link: <a href="http://www.allaboutcookies.org/">allaboutcookies.org</a>
|
|
||||||
|
|
||||||
</p>
|
|
||||||
<hr/>
|
|
||||||
<p>
|
|
||||||
7. Contact Information
|
|
||||||
<br />
|
|
||||||
If you have more questions, please contact us at this discord server: <a href="https://discord.gg/JEwYWGraj7">discord.gg/JEwYWGraj7</a>
|
|
||||||
</p>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
Before Width: | Height: | Size: 17 KiB |
|
@ -1,128 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<!-- Google tag (gtag.js) -->
|
|
||||||
<!--<script async src="https://www.googletagmanager.com/gtag/js?id=G-Q96FGB3L05"></script>
|
|
||||||
<script>
|
|
||||||
window.dataLayer = window.dataLayer || [];
|
|
||||||
function gtag() { dataLayer.push(arguments); }
|
|
||||||
gtag('js', new Date());
|
|
||||||
gtag('config', 'G-Q96FGB3L05');
|
|
||||||
</script>-->
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<title>FX Client</title>
|
|
||||||
<meta name="description" content="Modified Version of Territorial.io - FX Client">
|
|
||||||
<meta name="keywords"
|
|
||||||
content="territorial.io,territory games,territorial io,map games,conquest games,conquest game,david tschacher,territorial,territory game,io game,io games,territory.io,territory io,territory games io">
|
|
||||||
<meta name="author" content="MohsenEMX, peshomir,orlemley1, David Tschacher">
|
|
||||||
<meta name="viewport" content="width=device-width, maximum-scale=1">
|
|
||||||
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
|
|
||||||
<link rel="manifest" href="manifest.json" />
|
|
||||||
|
|
||||||
<meta name="og:image" content="https://fxclient.github.io/FXclient/assets/logo.png" />
|
|
||||||
<meta property="og:url" content="https://fxclient.github.io/FXclient/">
|
|
||||||
<meta property="og:type" content="website">
|
|
||||||
<meta property="og:title" content="FX Client">
|
|
||||||
<meta property="og:description" content="Modified Version of Territorial.io - FX Client">
|
|
||||||
<meta property="og:image" content="https://fxclient.github.io/FXclient/assets/logo.png">
|
|
||||||
<meta name="twitter:card" content="summary">
|
|
||||||
<meta name="twitter:title" content="FX Client">
|
|
||||||
<meta name="twitter:description" content="Modified Version of Territorial.io - FX Client">
|
|
||||||
<meta name="twitter:image" content="https://fxclient.github.io/FXclient/assets/logo.png">
|
|
||||||
<meta itemprop="name" content="FX Client">
|
|
||||||
<meta itemprop="description" content="Modified Version of Territorial.io - FX Client">
|
|
||||||
<meta itemprop="image" content="https://fxclient.github.io/FXclient/assets/logo.png">
|
|
||||||
|
|
||||||
<!-- FX Client CSS -->
|
|
||||||
<link rel="stylesheet" href="main.css?buildTimestamp">
|
|
||||||
<!-- Game CSS -->
|
|
||||||
<style>
|
|
||||||
html,
|
|
||||||
body {
|
|
||||||
overflow: hidden;
|
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
background: rgb(0, 0, 0);
|
|
||||||
color: rgb(255, 255, 255);
|
|
||||||
}
|
|
||||||
|
|
||||||
* {
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: rgb(225, 225, 255);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body onload="aiCommand746(0);">
|
|
||||||
<canvas id="canvasA" width="128" height="128"></canvas>
|
|
||||||
<div class="window flex settings" style="display:none">
|
|
||||||
<h1>Settings</h1>
|
|
||||||
<div class="scrollable">
|
|
||||||
<!--<label title="Name of the font to be used for rendering. For example: Arial, Georgia, sans-serif, serif, Comic Sans MS, ...">
|
|
||||||
Font name: <input id="settings_fontname" placeholder="Enter font name" value="Arial"></label><br>
|
|
||||||
<br><button onclick="removeWins()">Reset Wins Counter</button><br><br>
|
|
||||||
<!- -<label for="settings_donations_bots" class="checkbox">
|
|
||||||
Display donations from bots in donation history viewer (applies to multiplayer only)
|
|
||||||
<input type="checkbox" id="settings_donations_bots"><span class="checkmark"></span>
|
|
||||||
</label><br>- ->
|
|
||||||
<label for="settings_displaywincounter" class="checkbox">
|
|
||||||
Display win counter
|
|
||||||
<input type="checkbox" id="settings_displaywincounter"><span class="checkmark"></span>
|
|
||||||
</label><br>
|
|
||||||
<label for="settings_usefullscreenmode" class="checkbox">
|
|
||||||
Use fullscreen mode<br>
|
|
||||||
<small>Note: fullscreen mode will trigger after you click anywhere on the page due to browser policy restrictions.</small>
|
|
||||||
<input type="checkbox" id="settings_usefullscreenmode"><span class="checkmark"></span>
|
|
||||||
</label><br>
|
|
||||||
<label for="settings_hidealllinks" class="checkbox">
|
|
||||||
Hide Links option also hides app store links
|
|
||||||
<input type="checkbox" id="settings_hidealllinks"><span class="checkmark"></span>
|
|
||||||
</label><br>
|
|
||||||
<label for="settings_realisticnames" class="checkbox">
|
|
||||||
Realistic Bot Names
|
|
||||||
<input type="checkbox" id="settings_realisticnames"><span class="checkmark"></span>
|
|
||||||
</label><br>
|
|
||||||
<label for="settings_showPlayerDensity" class="checkbox">
|
|
||||||
Show player density
|
|
||||||
<input type="checkbox" id="settings_showPlayerDensity"><span class="checkmark"></span>
|
|
||||||
</label><br>
|
|
||||||
<label title="Controls how the territorial density value should be rendered">
|
|
||||||
Density value display style: <select id="settings_densityDisplayStyle">
|
|
||||||
<option value="percentage">Percentage</option>
|
|
||||||
<option value="absoluteQuotient">Value from 0 to 150 (BetterTT style)</option>
|
|
||||||
</select></label><br><br>
|
|
||||||
<label title="A custom image to be shown in the main menu background instead of the currently selected map.">
|
|
||||||
Custom main menu background: <input id="settings_custombackgroundurl" placeholder="Enter an image URL here"></label>
|
|
||||||
<!- -<input type="file" id="customBackgroundFileInput" style="display:none;">
|
|
||||||
or <button onclick="openCustomBackgroundFilePicker()">Open a local file</button>- -><br><br>
|
|
||||||
<!- -<label for="settings_custommapfileinput" class="checkbox">
|
|
||||||
Bring back the custom map file button after the creator removed it in 1.83.0
|
|
||||||
<input type="checkbox" id="settings_custommapfileinput"><span class="checkmark"></span>
|
|
||||||
</label>- ->
|
|
||||||
<p>Attack Percentage Keybinds</p>
|
|
||||||
<div id="keybinds" class="arrayinput"></div>
|
|
||||||
<button id="keybindAddButton">Add</button>-->
|
|
||||||
</div>
|
|
||||||
<hr>
|
|
||||||
<footer>
|
|
||||||
<button onclick="settingsManager.resetAll()">Reset Settings</button>
|
|
||||||
<button onclick="settingsManager.save()">Save Settings</button>
|
|
||||||
</footer>
|
|
||||||
</div>
|
|
||||||
<div class="window scrollable selectable" id="playerlist" style="display: none;">
|
|
||||||
<h1>Player List</h1>
|
|
||||||
<table><tbody id="playerlist_content"></tbody></table>
|
|
||||||
</div>
|
|
||||||
<div class="window scrollable selectable" id="donationhistory" style="display:none">
|
|
||||||
<h1>Donation history for </h1>
|
|
||||||
<p id="donationhistory_note">Note: donations from bots are not shown here</p>
|
|
||||||
<table><tbody id="donationhistory_content"></tbody></table>
|
|
||||||
</div>
|
|
||||||
<script src="variables.js?buildTimestamp"></script>
|
|
||||||
<script src="fx_core.js?buildTimestamp"></script>
|
|
||||||
<script src="game.js?buildTimestamp"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
208
static/main.css
|
@ -1,208 +0,0 @@
|
||||||
.scrollable {
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
::-webkit-scrollbar {
|
|
||||||
width: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
::-webkit-scrollbar-thumb {
|
|
||||||
background-color: #aaaaaa;
|
|
||||||
}
|
|
||||||
|
|
||||||
.window {
|
|
||||||
position : fixed;
|
|
||||||
background-color: rgba(0, 0, 0, 0.7);
|
|
||||||
width : 90%;
|
|
||||||
top : 0;
|
|
||||||
color : white;
|
|
||||||
font-family : 'Franklin Gothic Medium', 'Trebuchet MS', Arial, sans-serif;
|
|
||||||
margin : auto;
|
|
||||||
margin-top : 20px;
|
|
||||||
right : 0;
|
|
||||||
left : 0;
|
|
||||||
padding : 15px;
|
|
||||||
box-sizing : border-box;
|
|
||||||
border-color : white;
|
|
||||||
border-style : solid;
|
|
||||||
border-width : 2px;
|
|
||||||
border-width : calc(0.15 * (1vw + 1vh));
|
|
||||||
font-size : 20px;
|
|
||||||
font-size : calc(14px + ((0.4 * (0.8vw + 1vh)) + 0.15rem));
|
|
||||||
max-height : 90%;
|
|
||||||
transition : 0.2s;
|
|
||||||
z-index : 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
.window.flex {
|
|
||||||
display : flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
hr {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.window button,
|
|
||||||
.window input,
|
|
||||||
.window select {
|
|
||||||
background-color: rgba(0, 0, 0, 0.7);
|
|
||||||
color : white;
|
|
||||||
font-size : 20px;
|
|
||||||
font-size : 0.9em;
|
|
||||||
padding : 0.4rem;
|
|
||||||
transition : 0.2s;
|
|
||||||
border : 1px solid #fff;
|
|
||||||
border-radius : 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
font-weight : normal;
|
|
||||||
margin-block-start: 0.5em;
|
|
||||||
margin-block-end : 0.5em;
|
|
||||||
transition : 0.2s;
|
|
||||||
}
|
|
||||||
#playerlist h1 {
|
|
||||||
margin-block-start: 0.3em;
|
|
||||||
margin-block-end : 0.3em;
|
|
||||||
}
|
|
||||||
h3 {
|
|
||||||
font-weight : normal;
|
|
||||||
margin-block-start: 0.6em;
|
|
||||||
margin-block-end : 0.6em;
|
|
||||||
}
|
|
||||||
|
|
||||||
canvas,
|
|
||||||
input,
|
|
||||||
textarea {
|
|
||||||
transition: 0.2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
button:hover {
|
|
||||||
background-color: rgba(222, 222, 222, 0.52);
|
|
||||||
border-radius : 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.window input:focus {
|
|
||||||
background-color: rgba(222, 222, 222, 0.36);
|
|
||||||
border-radius : 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
td {
|
|
||||||
padding: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#playerlist_content.clickable td { cursor: pointer; }
|
|
||||||
#playerlist_content.clickable td:hover { background-color: #00ff0040; }
|
|
||||||
|
|
||||||
tr.new {
|
|
||||||
animation: flashAnimation 0.4s ease-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes flashAnimation {
|
|
||||||
0% {
|
|
||||||
background-color: #ffffffaa;
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
table {
|
|
||||||
border-spacing: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
input#userna,
|
|
||||||
input#inputfilebtn {
|
|
||||||
transition: 0.2s
|
|
||||||
}
|
|
||||||
|
|
||||||
.selectable {
|
|
||||||
user-select: text;
|
|
||||||
}
|
|
||||||
|
|
||||||
.color-red {
|
|
||||||
color: #dc143c;
|
|
||||||
}
|
|
||||||
|
|
||||||
.color-green {
|
|
||||||
color: #32cd32;
|
|
||||||
}
|
|
||||||
|
|
||||||
.color-light-gray {
|
|
||||||
color: #aaaaaa;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Checkbox */
|
|
||||||
label.checkbox {
|
|
||||||
display : block;
|
|
||||||
position : relative;
|
|
||||||
padding-left : 35px;
|
|
||||||
/*margin-bottom: 12px;*/
|
|
||||||
cursor : pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
label.checkbox input {
|
|
||||||
position: absolute;
|
|
||||||
opacity : 0;
|
|
||||||
cursor : pointer;
|
|
||||||
height : 0;
|
|
||||||
width : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.checkmark {
|
|
||||||
position : absolute;
|
|
||||||
top : 0;
|
|
||||||
left : 0;
|
|
||||||
height : 25px;
|
|
||||||
width : 25px;
|
|
||||||
/*background-color: #eee;*/
|
|
||||||
background-color : rgb(255 255 255 / 70%);
|
|
||||||
}
|
|
||||||
|
|
||||||
label.checkbox:hover .checkmark {
|
|
||||||
background-color: #ccc;
|
|
||||||
}
|
|
||||||
|
|
||||||
label.checkbox input:checked~.checkmark {
|
|
||||||
/*background-color: #2196F3;*/
|
|
||||||
background-color: rgba(0, 255, 0, 0.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
.checkmark::after {
|
|
||||||
content : "";
|
|
||||||
position: absolute;
|
|
||||||
display : none;
|
|
||||||
}
|
|
||||||
|
|
||||||
label.checkbox input:checked~.checkmark:after {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
label.checkbox .checkmark:after {
|
|
||||||
left : 9px;
|
|
||||||
top : 5px;
|
|
||||||
width : 5px;
|
|
||||||
height : 10px;
|
|
||||||
border : solid white;
|
|
||||||
border-width : 0 3px 3px 0;
|
|
||||||
-webkit-transform: rotate(45deg);
|
|
||||||
-ms-transform : rotate(45deg);
|
|
||||||
transform : rotate(45deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Custom Map Button */
|
|
||||||
::-webkit-file-upload-button {
|
|
||||||
color : white;
|
|
||||||
background-color: #120076;
|
|
||||||
border : 2px solid #fff;
|
|
||||||
top : 0;
|
|
||||||
bottom : 0;
|
|
||||||
padding-top : 20px;
|
|
||||||
padding-bottom : 20px;
|
|
||||||
padding-left : 20px;
|
|
||||||
padding-right : 20px;
|
|
||||||
font-family : 'Trebuchet MS', 'Arial Narrow', Arial, sans-serif;
|
|
||||||
text-align : center;
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
{
|
|
||||||
"name": "FX Client",
|
|
||||||
"short_name": "FXclient",
|
|
||||||
"start_url": ".",
|
|
||||||
"display": "standalone",
|
|
||||||
"background_color": "#000000",
|
|
||||||
"description": "Client for Territorial.io",
|
|
||||||
"icons": [
|
|
||||||
{
|
|
||||||
"src": "favicon.ico",
|
|
||||||
"sizes": "64x64"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"src": "assets/logo.png",
|
|
||||||
"sizes": "any",
|
|
||||||
"type": "image/png"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -1,96 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>FX Client - Privacy Policy</title>
|
|
||||||
<meta name="og:image" content="https://fxclient.github.io/FXclient/assets/logo.png" />
|
|
||||||
<meta property="og:image" content="https://fxclient.github.io/FXclient/assets/logo.png">
|
|
||||||
<link rel="shortcut icon" href="https://fxclient.github.io/FXclient/favicon.ico" type="image/x-icon">
|
|
||||||
<meta property="og:title" content="FX Client">
|
|
||||||
<meta name="description" content="FX Client Privacy Policy">
|
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
text-align: center;
|
|
||||||
background-color: #fff;
|
|
||||||
color: #000;
|
|
||||||
font-size: 25px;
|
|
||||||
font-family: 'Gill Sans', 'Gill Sans MT', Calibri, 'Trebuchet MS', sans-serif;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
#dd {
|
|
||||||
text-align: center;
|
|
||||||
background-color: #fff;
|
|
||||||
color: #000;
|
|
||||||
font-size: 40px;
|
|
||||||
font-family: 'Gill Sans', 'Gill Sans MT', Calibri, 'Trebuchet MS', sans-serif;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
text-decoration: none;
|
|
||||||
transition: 0.2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
color: red;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<span id="dd">Privacy Policy</span>
|
|
||||||
|
|
||||||
<p>Last Update: 29 March 2024</p>
|
|
||||||
|
|
||||||
<p>1. General Notes
|
|
||||||
<br />
|
|
||||||
Unless otherwise indicated, this privacy policy applies for the website (<a href="https://fxclient.github.io/FXclient/">fxclient.github.io/FXclient/</a>).
|
|
||||||
|
|
||||||
In this policy, "fxclient", "we" or "us" refers to a group of developers scattered around the world. The
|
|
||||||
contact information of the owner of this enterprise can be found below.
|
|
||||||
</p>
|
|
||||||
<hr />
|
|
||||||
<p>2. Third Parties
|
|
||||||
<br />
|
|
||||||
We don't share your information with any 3rd parties.
|
|
||||||
</p>
|
|
||||||
<hr />
|
|
||||||
<p>
|
|
||||||
3. What information do we collect?
|
|
||||||
<br />
|
|
||||||
We do not collect any user information. Information is collected by territorial.io. The privacy policy for
|
|
||||||
territorial.io can be found at <a href="https://territorial.io/privacy_policy">
|
|
||||||
territorial.io/privacy_policy </a>
|
|
||||||
<br />
|
|
||||||
On the website we collect cookies: If you need more information about our cookies, you may check out our cookie
|
|
||||||
policy: <a href="https://fxclient.github.io/FXclient/cookie_policy">fxclient.github.io/FXclient/cookie_policy</a>
|
|
||||||
</p>
|
|
||||||
<hr />
|
|
||||||
<p>
|
|
||||||
4. How do we collect and use your information?
|
|
||||||
<br />
|
|
||||||
Information is sent to and used by Territorial.io and not encrypted in transit. Your information is used to
|
|
||||||
improve the game and to prevent fraud. Collection and usage of the data by Territorial.io is explained in more
|
|
||||||
detail at <a href="https://territorial.io/privacy_policy"> territorial.io/privacy_policy </a>
|
|
||||||
Usernames and rankings are publicly available. Statistical and anonymous game data are shown on Territorial.io
|
|
||||||
(<a href="https://territorial.io/players">territorial.io/players</a> and <a href="https://territorial.io/clans">territorial.io/clans</a>).
|
|
||||||
</p>
|
|
||||||
<hr />
|
|
||||||
<p>
|
|
||||||
5. How can you delete your information?
|
|
||||||
<br />
|
|
||||||
Your data will be automatically deleted after 6 months of inactivity.
|
|
||||||
</p>
|
|
||||||
<hr />
|
|
||||||
<p>
|
|
||||||
6. Contact Information
|
|
||||||
<br />
|
|
||||||
If you have more questions, please contact us at this discord server: <a href="https://discord.gg/JEwYWGraj7">discord.gg/JEwYWGraj7</a>
|
|
||||||
</p>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 7.4 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |