diff --git a/build.js b/build.js index 0db4313..2a65234 100644 --- a/build.js +++ b/build.js @@ -35,6 +35,8 @@ let dictionary = {}; /\w+\.\w+\((\w+)\)\?\w+\.\w+\(\1\)\?(\w+)=(\w+\.\w+)\(13,\[\2\]\):\(\w+=\w+\.\w+\(\1\),\2=\3\(14,\[(?\w+)\[(\w+)\],(\w+\.\w+\.\w+\()(?\w+)\[\5\]\),\6(?\w+)\[\5\]\),\2\]\),\w+=!0\):\2=/g, // this one also broke in 1.91.3 /,\w+="Player: "\+(?\w+)\[\w+\],\w+=\(\w\+=" Balance: "\+\w+\.\w+\((?\w+)\[\w+\]\)\)\+\(" Territory: "\+\w+\.\w+\((?\w+)\[\w+\]\)\)\+\(" Coords: "/g, /\((?\w+)=Math\.floor\(\(\w+\?\.0114:\.01296\)\*\w+\)\)/g, + /(function \w+\((\w+),(\w+),(\w+),(\w+),(\w+)\){\6\.fillText\((?\w+)\[\2\],\4,\5\)),(\2<(?\w+)&&2!==(?\w+)\[)/g, + /,\w+=512,(?\w+)=\w+,(?\w+)&&\(\1=\w+\.\w+\(\)\),\w+=\1-\w+,\w+=0,/g ].forEach(expression => { result = expression.exec(script); if (result === null) throw new Error("no match for ") + expression; @@ -139,7 +141,7 @@ replaceOne(/(this\.\w+=function\((\w+),(\w+)\)\{)(\2===\w+&&\(\w+\.\w+\((\w+\.\w // Display donations for a player when clicking on them in the leaderboard // match , 0 !== dG[x]) && fq.hB(x, 800, false, 0), replaceOne(/,(0!==\w+\[(\w+)\]\)&&\w+\.\w+\(\2,800,!1,0\),)/g, - `, ${dictionary.gIsTeamGame} && displayDonationsHistory($2, ${dictionary.playerNames}, ${dictionary.gIsSingleplayer}), $1`); + `, ${dictionary.gIsTeamGame} && donationsTracker.displayHistory($2, ${dictionary.playerNames}, ${dictionary.gIsSingleplayer}), $1`); // Reset donation history when a new game is started replaceOne(new RegExp(`,${dictionary.playerBalances}=new Uint32Array\\(\\w+\\),`, "g"), "$& donationsTracker.reset(), "); diff --git a/static/fx_core.js b/static/fx_core.js index 9d41e46..68c8b87 100644 --- a/static/fx_core.js +++ b/static/fx_core.js @@ -1,5 +1,5 @@ -const fx_version = '0.6.2'; // FX Client Version -const fx_update = 'Mar 8'; // FX Client Last Updated +const fx_version = '0.6.2.1'; // FX Client Version +const fx_update = 'Mar 10'; // FX Client Last Updated if (localStorage.getItem("fx_winCount") == undefined || localStorage.getItem("fx_winCount") == null) { var wins_counter = 0; @@ -200,6 +200,7 @@ var WindowManager = new (function() { 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) { @@ -217,7 +218,8 @@ WindowManager.add({ 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", @@ -236,11 +238,14 @@ const playerList = new (function () { 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"), displayDonationsHistory(playerId); + if (getVar("gIsTeamGame")) WindowManager.closeWindow("playerList"), donationsTracker.displayHistory(playerId); }); this.display = function displayPlayerList(playerNames) { - let listContent = ""; - for (let i = 0; i < playerNames.length; i++) { + const gHumans = getVar("gHumans"); + const gLobbyMaxJoin = getVar("gLobbyMaxJoin"); + let listContent = `

Players (${gHumans})

`; + for (let i = 0; i < gLobbyMaxJoin; i++) { + if (i === gHumans) listContent += `

Bots (${gLobbyMaxJoin - gHumans})

`; listContent += `${i}. ${escapeHtml(playerNames[i])}` } document.getElementById("playerlist_content").innerHTML = listContent; @@ -260,38 +265,50 @@ const playerList = new (function () { } }); 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 - // from inside of game: - // ((!gE[g].startsWith("[Bot] ") || settings.showBotDonations) && donationsTracker.logDonation(g,k,x)) + 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)); + } }; - this.getRecipientHistoryOf = function(playerID) { - return this.donationHistory[playerID]; - }; - this.reset = function() { for (var i = 0; i < 512; i++) this.donationHistory[i] = []; }; -}); -function displayDonationsHistory(playerID, playerNames = getVar("playerNames"), isSingleplayer = getVar("gIsSingleplayer")) { - var history = donationsTracker.getRecipientHistoryOf(playerID); - console.log("History for " + playerNames[playerID] + ":"); - console.log(history); - document.querySelector("#donationhistory h1").innerHTML = "Donation history for " + escapeHtml(playerNames[playerID]); - var historyText = ""; - history.reverse(); - if (history.length > 0) history.forEach(function(historyItem, index) { - historyText += `${(history.length - index)}. `; + function generateTableRowItem(historyItem, index, playerID, isNew) { + const playerNames = getVar("playerNames"); + const row = document.createElement("tr"); + if (isNew) row.setAttribute("class", "new"); + let content = `${index}. `; if (playerID === historyItem[1]) - historyText += `Received ${historyItem[2]} resources from ${escapeHtml(playerNames[historyItem[0]])}
`; - else historyText += `Sent ${historyItem[2]} resources to ${escapeHtml(playerNames[historyItem[1]])}
`; - }); - else historyText = "Nothing to display"; - document.querySelector("#donationhistory p#donationhistory_text").innerHTML = historyText; - WindowManager.openWindow("donationHistory", isSingleplayer); -} + content += `Received ${historyItem[2]} resources from ${escapeHtml(playerNames[historyItem[0]])}`; + else content += `Sent ${historyItem[2]} resources to ${escapeHtml(playerNames[historyItem[1]])}`; + content += ""; + 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(); }; diff --git a/static/index.html b/static/index.html index 5070a3f..0068d66 100644 --- a/static/index.html +++ b/static/index.html @@ -117,7 +117,7 @@ diff --git a/static/main.css b/static/main.css index 23de157..98be205 100644 --- a/static/main.css +++ b/static/main.css @@ -16,7 +16,7 @@ width : 90%; top : 0; color : white; - font-family : 'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif; + font-family : 'Franklin Gothic Medium', 'Trebuchet MS', Arial, sans-serif; margin : auto; margin-top : 20px; right : 0; @@ -62,6 +62,15 @@ h1 { 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, @@ -86,6 +95,19 @@ td { #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; }