Compare commits
3 Commits
ce2e2468fd
...
ad6f0e2f05
Author | SHA1 | Date |
---|---|---|
peshomir | ad6f0e2f05 | |
peshomir | 9e45327969 | |
peshomir | 0e4ecbb36f |
125
build.js
125
build.js
|
@ -78,7 +78,8 @@ const generateRegularExpression = (/** @type {string} */ code, /** @type {boolea
|
|||
// 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
|
||||
/,\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 = [
|
||||
|
@ -219,26 +220,35 @@ replaceOne(/(this\.\w+=function\((\w+),(\w+)\)\{)(\2===\w+&&\(\w+\.\w+\((\w+\.\w
|
|||
"$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`);
|
||||
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 when a new game is started
|
||||
replaceOne(new RegExp(`,${dictionary.playerBalances}=new Uint32Array\\(\\w+\\),`, "g"), "$& donationsTracker.reset(), ");
|
||||
// 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
|
||||
{ // 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 mouseDown
|
||||
replaceOne(/(this\.\w+=function\((?<x>\w+),(?<y>\w+)\){return!!\w+\(\2,\3\))&&(\(\w+=\w+\.\w+,)/g,
|
||||
`$1 && (${buttonBoundsCheck} && playerList.display(${dictionary.playerNames}), true) && $4`);
|
||||
// Handle player list button hover
|
||||
// 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,
|
||||
`$1 if (${buttonBoundsCheck}) { playerList.hoveringOverButton === false && (playerList.hoveringOverButton = true, ${drawFunction}(), $<setRepaintNeeded>); } `
|
||||
+ ` else { playerList.hoveringOverButton === true && (playerList.hoveringOverButton = false, ${drawFunction}(), $<setRepaintNeeded>); } $4`);
|
||||
`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
|
||||
|
@ -250,6 +260,97 @@ replaceOne(new RegExp(`,${dictionary.playerBalances}=new Uint32Array\\(\\w+\\),`
|
|||
`$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);');
|
||||
|
|
19
readme.md
19
readme.md
|
@ -20,21 +20,22 @@ FX Client is the first Territorial.io client, targeting better User Interface an
|
|||
|
||||
## Features:
|
||||
1. It's 100% free and open source on Github
|
||||
2. It's Ad free and removes game's default ads.
|
||||
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 win counter
|
||||
7. Adds a player list
|
||||
8. Adds the ability to view the history of who donated to a player during the game by clicking on their name in the leaderboard or the player list
|
||||
9. Can be installed as a PWA (progressive web app) ensuring maximum enjoyment on consoles, phones and even desktop devices
|
||||
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:
|
||||
|
||||
10. Change the game font
|
||||
11. Make fullscreen mode trigger automatically
|
||||
12. Set a custom main menu background
|
||||
13. Create custom attack percentage keybinds
|
||||
12. Make fullscreen mode trigger automatically
|
||||
13. Set a custom main menu background
|
||||
14. Create custom attack percentage keybinds
|
||||
|
||||
## Building Locally
|
||||
|
||||
|
|
134
src/fx_core.js
134
src/fx_core.js
|
@ -1,5 +1,5 @@
|
|||
const fx_version = '0.6.3.3'; // FX Client Version
|
||||
const fx_update = 'Apr 11'; // FX Client Last Updated
|
||||
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;
|
||||
|
@ -27,8 +27,9 @@ function KeybindsInput(containerElement) {
|
|||
this.keys = [ "key", "type", "value" ];
|
||||
this.objectArray = [];
|
||||
this.addObject = function () {
|
||||
this.objectArray.push({ key: "", type: "absolute", value: 1 });
|
||||
this.objectArray.push({ key: "", type: "absolute", value: 0.8 });
|
||||
this.displayObjects();
|
||||
keybindAddButton.scrollIntoView(false);
|
||||
};
|
||||
this.update = function () {
|
||||
this.objectArray = settings.attackPercentageKeybinds;
|
||||
|
@ -54,11 +55,15 @@ function KeybindsInput(containerElement) {
|
|||
inputField.setAttribute("placeholder", "No key set");
|
||||
inputField.addEventListener("click", this.startKeyInput.bind(this, i, key));
|
||||
} else { // key === "value"
|
||||
inputField.type = "number";
|
||||
inputField.setAttribute("step", "0.1");
|
||||
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));
|
||||
}
|
||||
inputField.value = this.objectArray[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);
|
||||
|
@ -83,10 +88,21 @@ function KeybindsInput(containerElement) {
|
|||
//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" ? parseFloat(event.target.value) : property === "key" ? event.key : event.target.value;
|
||||
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();
|
||||
};
|
||||
|
@ -104,6 +120,7 @@ var settings = {
|
|||
//"showBotDonations": false,
|
||||
"displayWinCounter": true,
|
||||
"useFullscreenMode": false,
|
||||
"hoveringTooltip": true,
|
||||
//"hideAllLinks": false,
|
||||
"realisticNames": false,
|
||||
"showPlayerDensity": true,
|
||||
|
@ -123,6 +140,8 @@ var settingsManager = new (function() {
|
|||
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" },
|
||||
|
@ -322,6 +341,107 @@ const playerList = new (function () {
|
|||
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");
|
||||
|
|
Loading…
Reference in New Issue