您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Adds an healthbar, energybar, links and other QOL to BiteFight
当前为
// ==UserScript== // @name Better BiteFight // @namespace https://lobby.bitefight.gameforge.com/ // @version 0.7.7 // @description Adds an healthbar, energybar, links and other QOL to BiteFight // @author Spychopat // @match https://*.bitefight.gameforge.com/* // @icon https://lobby.bitefight.gameforge.com/favicon.ico // @grant GM_getValue // @grant GM_setValue // @grant GM_addStyle // ==/UserScript== (function () { 'use strict'; // Script storage keys const KEY_SERVER_DOMAIN = window.location.hostname; const pageLoadTime = Date.now(); // uncomment to reset character data if needed //GM_setValue(KEY_SERVER_DOMAIN, {}) //GM_setValue(KEY_SERVER_DOMAIN+"/grotto_stats", {}) // Define character object const CHARACTER = GM_getValue(KEY_SERVER_DOMAIN, { energy: 0, maxEnergy: 0, health: 0, maxHealth: 0, regenHealth: 0, potionCooldownEnd: 0, churchCooldownEnd: 0, autoRedirectGrotte: false, autoGrotto: [false, false, false], lastGrottoClick: -1 }); const GROTTO_STATS = GM_getValue(KEY_SERVER_DOMAIN+"/grotto_stats", { goldEarned: { 0: [], 1: [], 2: [] }, dmgTaken: { 0: [], 1: [], 2: [] }, xpEarned: { 0: [], 1: [], 2: [] } }); //console.log(parseInt(formatNumber(document.getElementsByClassName("gold")[1].firstChild.textContent.split("\n")[1]))); redirectAfterGrotteFight(); // run it first, because it has chances to redirect, so we don't work uselessly // early, to avoid the page jump as much as possible insertCSS(); addAdditionnalLink(); extractCharacterStats(); updatePotionTimer(); // Run the church cooldown update function if on the church page updateRegenHealth(); insertHealthEnergyBars(); // Insert progress bars after updating the character startHealthRegeneration(); // Start health regeneration on page load if (window.location.pathname.contains('/profile')){ moveGameEventDiv(); // move down the game event div } else if (window.location.pathname.contains('/city/church')){ updateChurchCooldownTimer(); } else if (window.location.pathname.contains('/city/grotte')){ addGrottoAutoRedirectCheckBox(); addAutoGrottoButton(); autoFightGrotto(); } else if (window.location.pathname.contains('/city/shop')){ defaultNonPremiumShop(); } updateCharacter(); //console.log(CHARACTER); function insertCSS() { GM_addStyle(` #upgrademsg { display: none; } #premium > img { display: none; } #mmonetbar { display: none !important; visibility: hidden; } .premiumButton { color: #FFCC33 !important; font-weight: bold !important; background-position: 0 -184px !important; text-shadow: 0 0 5px #000 !important; } `); } function extractCharacterStats(){ // Get Stats var allStatsElement = document.getElementsByClassName("gold")[0]; var statsValues = allStatsElement.textContent.split("\n"); statsValues = statsValues.map(value => value.trim()); statsValues.shift(); // Extract energy, fragments, gold, health, and hellStones var energy = statsValues[3].trim(); var currentEnergy = energy.split("/")[0]; var maxEnergy = energy.split("/")[1]; if (currentEnergy && maxEnergy) { CHARACTER.energy = parseInt(currentEnergy); // Use parseFloat to preserve decimals CHARACTER.maxEnergy = parseInt(maxEnergy); // Use parseFloat to preserve decimals } var health = statsValues[4].trim(); var currentHealth = formatNumber(health.split("/")[0]); var maxHealth = formatNumber(health.split("/")[1]); if (currentHealth && maxHealth) { CHARACTER.health = parseInt(currentHealth); CHARACTER.maxHealth = parseInt(maxHealth); } CHARACTER.level = parseInt(statsValues[5].trim().split(" ")[0]); } // Format texts to return as numbers (no thousand separators) function formatNumber(value) { while (value.indexOf(".") > 0) value = value.replace(".", ""); return value; } function updateRegenHealth() { if (!window.location.pathname.endsWith('/profile/index')) return; var elements = document.getElementsByClassName("triggerTooltip"); // Loop through the elements for (let i = 0; i < elements.length; i++) { // Check if the inner text or inner HTML contains "/ h" if (elements[i].innerText.includes("/ h") || elements[i].innerHTML.includes("/ h")) { CHARACTER.regenHealth = parseInt(elements[i].textContent); //console.log("Regen per hour found : ", parseInt(elements[i].textContent)); break; // Exit the loop once the element is found } } } // Update character in local storage function updateCharacter() { GM_setValue(KEY_SERVER_DOMAIN, CHARACTER); } function updateGrottoStats(){ GM_setValue(KEY_SERVER_DOMAIN+"/grotto_stats", GROTTO_STATS); } function updatePotionTimer() { if (!window.location.pathname.endsWith('/profile/index')) return; // Ensure this only runs on the right page // Get all elements with the class "inactive" const inactiveElements = document.getElementsByClassName('inactive'); let targetElement = null; // Loop through each "inactive" element to find the target for (const inactiveElement of inactiveElements) { // Find elements with the class "countdown_row countdown_amount" within the current "inactive" element const matchingElements = inactiveElement.getElementsByClassName('countdown_row countdown_amount'); if (matchingElements.length > 0) { targetElement = matchingElements[0]; // Take the first matching element break; // Stop once we find the target } } if (targetElement) { // Get the current time and add the potion cooldown to get the end time const currentTime = new Date().getTime() / 1000; // Current time in seconds const cooldownTime = timeToSeconds(targetElement.textContent); // Convert cooldown time to seconds const endTime = currentTime + cooldownTime; // Calculate the end time // Save the end time to the character object CHARACTER.potionCooldownEnd = endTime; updateCharacter(); // Save updated character data } } function timeToSeconds(timeStr) { const [hours, minutes, seconds] = timeStr.split(':').map(Number); return (hours * 3600) + (minutes * 60) + seconds; } function insertHealthEnergyBars() { if (document.getElementById('progressBarsTimersContainer')) { return; } let mainContainer = document.createElement('div'); mainContainer.id = 'progressBarsTimersContainer'; mainContainer.style.display = 'flex'; mainContainer.style.flexDirection = 'column'; // Stack the bars and timers vertically mainContainer.style.alignItems = 'center'; mainContainer.style.marginTop = '3px'; let progressBarsContainer = document.createElement('div'); progressBarsContainer.style.display = 'flex'; // Changed to row to place bars side by side progressBarsContainer.style.flexDirection = 'row'; // Set to row for horizontal alignment progressBarsContainer.style.alignItems = 'center'; // Align items vertically in the middle progressBarsContainer.style.paddingBottom = '5px'; progressBarsContainer.style.gap = '60px'; // Added gap between the bars // Health Bar let healthBarContainer = document.createElement('div'); healthBarContainer.style.width = '250px'; healthBarContainer.style.position = 'relative'; healthBarContainer.style.background = 'linear-gradient(to right, #1a1a1a, #333)'; healthBarContainer.style.borderImage = 'linear-gradient(to right, #ff4d4d, #b80000) 1'; healthBarContainer.style.borderRadius = '6px'; healthBarContainer.style.boxShadow = 'inset 0 10px 5px rgba(0, 0, 0, 0.5), 0 0 10px rgba(255, 77, 77, 1)'; healthBarContainer.style.overflow = 'hidden'; healthBarContainer.id = 'healthProgressBar'; let healthBar = document.createElement('div'); healthBar.style.height = '20px'; healthBar.style.width = `${(CHARACTER.health / CHARACTER.maxHealth) * 100}%`; healthBar.style.background = 'linear-gradient(to right, #ff4d4d, #b80000)'; healthBar.style.transition = 'width 0.3s ease-in-out'; healthBar.style.boxShadow = 'inset 0 10px 5px rgba(0, 0, 0, 0.5)'; let healthText = document.createElement('div'); healthText.textContent = `${CHARACTER.health > 999 ? CHARACTER.health.toString().replace(/\B(?=(\d{3})+(?!\d))/g, '.') : CHARACTER.health}`; healthText.style.position = 'absolute'; healthText.style.top = '50%'; healthText.style.left = '50%'; healthText.style.transform = 'translate(-50%, -50%)'; healthText.style.color = 'white'; healthText.style.fontSize = '12px'; healthText.style.fontFamily = 'monospace'; healthBarContainer.appendChild(healthBar); healthBarContainer.appendChild(healthText); // Energy Bar let energyBarContainer = document.createElement('div'); energyBarContainer.style.width = '250px'; energyBarContainer.style.position = 'relative'; energyBarContainer.style.background = 'linear-gradient(to right, #1a1a1a, #333)'; energyBarContainer.style.borderImage = 'linear-gradient(to right, #4d94ff, #0000a4) 1'; energyBarContainer.style.borderRadius = '6px'; energyBarContainer.style.boxShadow = 'inset 0 10px 5px rgba(0, 0, 0, 0.5), 0 0 10px rgba(77, 148, 255, 1)'; energyBarContainer.style.overflow = 'hidden'; energyBarContainer.id = 'energyProgressBar'; let energyBar = document.createElement('div'); energyBar.style.height = '20px'; energyBar.style.width = `${(CHARACTER.energy / CHARACTER.maxEnergy) * 100}%`; energyBar.style.background = 'linear-gradient(to right, #4d94ff, #0000a4)'; energyBar.style.transition = 'width 0.3s ease-in-out'; energyBar.style.boxShadow = 'inset 0 10px 5px rgba(0, 0, 0, 0.5)'; let energyText = document.createElement('div'); energyText.textContent = `${CHARACTER.energy}`; energyText.style.position = 'absolute'; energyText.style.top = '50%'; energyText.style.left = '50%'; energyText.style.transform = 'translate(-50%, -50%)'; energyText.style.color = 'white'; energyText.style.fontSize = '12px'; energyText.style.fontFamily = 'monospace'; energyBarContainer.appendChild(energyBar); energyBarContainer.appendChild(energyText); progressBarsContainer.appendChild(healthBarContainer); progressBarsContainer.appendChild(energyBarContainer); mainContainer.appendChild(progressBarsContainer); document.getElementsByClassName("gold")[0].appendChild(mainContainer); } function calculateCurrentHealth(){ const regenPerSecond = CHARACTER.regenHealth / 3600; // Convert regenHealth from per hour to per second // Calculate the total health regenerated since the page loaded const elapsedSeconds = (Date.now() - pageLoadTime) / 1000; // Time elapsed in seconds const regeneratedHealth = regenPerSecond * elapsedSeconds; // Calculate the updated health, without modifying the original CHARACTER.health const updatedHealth = Math.min( CHARACTER.health + regeneratedHealth, CHARACTER.maxHealth ); return updatedHealth; } // Start real-time health regeneration function startHealthRegeneration() { const regenInterval = 200; // Update every 200 ms setInterval(() => { // Update the progress bar with the calculated health updateProgressBars(calculateCurrentHealth()); }, regenInterval); } // Update the existing progress bars function updateProgressBars(calculatedHealth) { // Update Energy Progress Bar //const energyBar = document.getElementById('energyProgressBar').children[0]; //energyBar.style.width = `${(CHARACTER.energy / CHARACTER.maxEnergy) * 100}%`; //const energyText = document.getElementById('energyProgressBar').children[1]; //energyText.textContent = `${CHARACTER.energy}`; // Update Health Progress Bar const healthBar = document.getElementById('healthProgressBar').children[0]; healthBar.style.width = `${(calculatedHealth / CHARACTER.maxHealth) * 100}%`; const healthText = document.getElementById('healthProgressBar').children[1]; // Format the health value with thousands separators let healthWithoutDecimals = Math.floor(calculatedHealth); healthText.textContent = `${healthWithoutDecimals > 999 ? healthWithoutDecimals.toString().replace(/\B(?=(\d{3})+(?!\d))/g, '.'): healthWithoutDecimals}`; } // Function to update the timer display function updatePotionCooldownDisplay() { const timerElement = document.getElementById('potionCooldownTimer'); const currentTime = new Date().getTime() / 1000; // Current time in seconds if (CHARACTER.potionCooldownEnd > currentTime) { const remainingTime = CHARACTER.potionCooldownEnd - currentTime; // Remaining time in seconds const hours = Math.floor(remainingTime / 3600); const minutes = Math.floor((remainingTime % 3600) / 60); const seconds = Math.round(remainingTime % 60); //timerElement.textContent = `Potion : ${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`; timerElement.textContent = `Potion : ${hours > 0 ? hours.toString().padStart(2, '0') + ':' : ''}${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`; timerElement.className = ""; } else { timerElement.textContent = 'Potion'; timerElement.className = "premiumButton"; } } // Add the church cooldown timer display function updateChurchCooldownTimer() { const churchCountdownElement = document.getElementsByClassName('hasCountdown')[0]; if (churchCountdownElement) { const cooldownTime = churchCountdownElement.textContent.trim(); const currentTime = new Date().getTime() / 1000; // Current time in seconds const cooldownSeconds = timeToSeconds(cooldownTime); // Convert cooldown time to seconds const endTime = currentTime + cooldownSeconds; // Calculate the end time // Save the end time to the character object CHARACTER.churchCooldownEnd = endTime; updateCharacter(); // Save updated character data } } // Function to update the church cooldown display function updateChurchCooldownDisplay() { const timerElement = document.getElementById('churchCooldownTimer'); const currentTime = new Date().getTime() / 1000; // Current time in seconds if (CHARACTER.churchCooldownEnd > currentTime) { const remainingTime = CHARACTER.churchCooldownEnd - currentTime; // Remaining time in seconds const hours = Math.floor(remainingTime / 3600); const minutes = Math.floor((remainingTime % 3600) / 60); const seconds = Math.round(remainingTime % 60); //timerElement.textContent = `Church : ${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`; timerElement.textContent = `Church : ${hours > 0 ? hours.toString().padStart(2, '0') + ':' : ''}${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`; timerElement.className = ""; } else { timerElement.textContent = 'Church'; timerElement.className = "premiumButton"; } } function addAdditionnalLink() { // make the overview link open the attributes by default document.querySelectorAll('#menuHead li a')[1].href="/profile/index#tabs-2"; // make the voodoo shop less flashy document.getElementById("premium").querySelector("img").remove(); document.getElementById("premium").removeAttribute("id"); //translation of all the menu in english, so everything is the same document.querySelectorAll('#menuHead li a')[0].textContent="News"; document.querySelectorAll('#menuHead li a')[1].textContent="Overview"; document.querySelectorAll('#menuHead li a')[2].textContent="Messages"; document.querySelectorAll('#menuHead li a')[3].textContent="Hideout"; document.querySelectorAll('#menuHead li a')[4].textContent="City"; document.querySelectorAll('#menuHead li a')[5].textContent="Hunt"; document.querySelectorAll('#menuHead li a')[6].textContent="Voodoo Shop"; document.querySelectorAll('#menuHead li a')[7].textContent="Clan"; document.querySelectorAll('#menuHead li a')[8].textContent="Buddy list"; document.querySelectorAll('#menuHead li a')[9].textContent="Notepad"; document.querySelectorAll('#menuHead li a')[10].textContent="Settings"; document.querySelectorAll('#menuHead li a')[11].textContent="Forum"; document.querySelectorAll('#menuHead li a')[12].textContent="Highscore"; document.querySelectorAll('#menuHead li a')[13].textContent="Search"; document.querySelectorAll('#menuHead li a')[14].textContent="Support"; document.querySelectorAll('#menuHead li a')[15].textContent="Leave game"; // Find the <li> containing the Chasse link const chasseListItem = document.querySelector('li.free-space > a[href$="/robbery/index"]'); if (chasseListItem) { // Navigate to the parent <li> element const chasseLi = chasseListItem.closest('li'); // Remove the class "free-space" chasseLi.removeAttribute('class'); if (window.location.pathname.contains('robbery')){ chasseLi.className = "active"; } // Create a new <li> for the Grotte link const grotteLi = document.createElement('li'); if (window.location.pathname.contains('/grotte')){ if (document.getElementsByClassName("active")[0])document.getElementsByClassName("active")[0].removeAttribute('class'); grotteLi.className = "active"; } grotteLi.innerHTML = '<a href="/city/grotte" target="_top">Grotto</a>'; const graveLi = document.createElement('li'); if (window.location.pathname.contains('/city/graveyard') || window.location.pathname.contains('/user/working')){ if (document.getElementsByClassName("active")[0])document.getElementsByClassName("active")[0].removeAttribute('class'); graveLi.className = "active"; } graveLi.innerHTML = '<a href="/city/graveyard" target="_top">Graveyard</a>'; const shopLi = document.createElement('li'); if (window.location.pathname.contains('/city/shop/')){ if (document.getElementsByClassName("active")[0])document.getElementsByClassName("active")[0].removeAttribute('class'); shopLi.className = "active"; } shopLi.innerHTML = '<a href="/city/shop/potions/&page=1&premiumfilter=nonpremium" target="_top">Merchant</a>'; const questsLi = document.createElement('li'); questsLi.className = "free-space"; if (window.location.pathname.contains('/city/missions')){ if (document.getElementsByClassName("active")[0])document.getElementsByClassName("active")[0].removeAttribute('class'); questsLi.className = "active free-space"; } questsLi.innerHTML = '<a href="/city/missions" target="_top">Quests</a>'; const potionLi = document.createElement('li'); potionLi.innerHTML = CHARACTER.level > 74 ? '<a id="potionCooldownTimer" href="/profile/useItem/2/20" target="_top">Potion</a>' : '<a id="potionCooldownTimer" href="/profile/useItem/2/2" target="_top">Potion</a>'; const churchLi = document.createElement('li'); churchLi.innerHTML = '<a id="churchCooldownTimer" href="/city/church" target="_top">Church</a>'; /* let potionTimer = document.createElement('a'); potionTimer.id = 'potionCooldownTimer'; potionTimer.style.color = 'white'; potionTimer.style.fontSize = '14px'; potionTimer.style.fontFamily = 'monospace'; potionTimer.style.margin = '0px'; potionTimer.href = CHARACTER.level > 74 ? '/profile/useItem/2/20' : '/profile/useItem/2/2'; potionTimer.textContent = 'Potion Cooldown: Calculating...'; let churchTimer = document.createElement('a'); churchTimer.id = 'churchCooldownTimer'; churchTimer.style.color = 'white'; churchTimer.style.fontSize = '14px'; churchTimer.style.fontFamily = 'monospace'; churchTimer.style.margin = '0px'; churchTimer.href = '/city/church'; churchTimer.textContent = 'Church Cooldown: Calculating...'; */ // Insert the new links (in reverse) chasseLi.insertAdjacentElement('afterend', churchLi); chasseLi.insertAdjacentElement('afterend', potionLi); chasseLi.insertAdjacentElement('afterend', questsLi); chasseLi.insertAdjacentElement('afterend', shopLi); chasseLi.insertAdjacentElement('afterend', graveLi); chasseLi.insertAdjacentElement('afterend', grotteLi); updatePotionCooldownDisplay(); setInterval(updatePotionCooldownDisplay, 1000); updateChurchCooldownDisplay(); setInterval(updateChurchCooldownDisplay, 1000); } } function moveGameEventDiv() { const gameEventDiv = document.getElementById('gameEvent'); const itemsDiv = document.getElementById('items'); if (gameEventDiv && itemsDiv) { itemsDiv.insertAdjacentElement('afterend', gameEventDiv); } //scroll up after upgrading a skill if (window.location.hash=='#tabs-2') window.scrollTo(0, 0); //if (window.location.hash=='#potions') document.getElementsByClassName("ui-accordion-header")[2].scrollIntoView({ behavior: 'smooth' }); } function defaultNonPremiumShop() { const links = document.querySelectorAll('a'); // Select all anchor elements links.forEach(link => { // Check if the link href contains '/city/shop/' if (link.href.includes('/city/shop')) { // If the URL doesn't already have a query string, add it if (!link.href.includes('&premiumfilter=nonpremium')) { link.href += '&premiumfilter=nonpremium'; } } }); /* var premiumfilter = document.querySelector('select[name="premiumfilter"]'); // Replace with the correct selector if necessary if (premiumfilter) { premiumfilter.value = 'nonpremium'; // Set default value to 'nonpremium' }*/ } function redirectAfterGrotteFight() { if (!(window.location.href.includes('report/fightreport/') && window.location.href.includes('/grotte')))return; //console.log("Current difficulty : "+CHARACTER.lastGrottoClick); if(CHARACTER.lastGrottoClick == 0 || CHARACTER.lastGrottoClick == 1 || CHARACTER.lastGrottoClick == 2){ saveGrottoStats(CHARACTER.lastGrottoClick); } // condition to redirect to last page if (CHARACTER.autoRedirectGrotte || CHARACTER.autoGrotto[0] || CHARACTER.autoGrotto[1] || CHARACTER.autoGrotto[2]) { // Redirect to '/city/grotte' window.location.href = '/city/grotte'; } } function addGrottoAutoRedirectCheckBox(){ const buildingDescElement = document.getElementsByClassName('buildingDesc')[0]; if (!buildingDescElement) return; // add the button for auto redirection const buttonAutoRedirect = document.createElement("button"); if (CHARACTER.autoRedirectGrotte){ buttonAutoRedirect.textContent = "Redirect : ON"; buttonAutoRedirect.className = "btn-small left btn-redirectGrotto premiumButton"; } else { buttonAutoRedirect.textContent = "Redirect : OFF"; buttonAutoRedirect.className = "btn-small left btn-redirectGrotto"; } buttonAutoRedirect.style.margin = "0px"; buttonAutoRedirect.style.padding = "0 0 5px"; // Add a click event listener buttonAutoRedirect.addEventListener("click", function (event) { CHARACTER.autoRedirectGrotte = !CHARACTER.autoRedirectGrotte; updateCharacter(); if (CHARACTER.autoRedirectGrotte){ buttonAutoRedirect.textContent = "Redirect : ON"; buttonAutoRedirect.className = "btn-small left btn-redirectGrotto premiumButton"; } else { buttonAutoRedirect.textContent = "Redirect : OFF"; buttonAutoRedirect.className = "btn-small left btn-redirectGrotto"; } }); // Insert the button after the target element buildingDescElement.appendChild(buttonAutoRedirect); // add the button to reset stats const button = document.createElement("button"); button.textContent = "Reset stats"; button.className = "btn-small left btn-resetGrotto"; button.style.margin = "0px"; button.style.padding = "0 0 5px"; // Add a click event listener button.addEventListener("click", function (event) { console.log("Grotto stats reset"); GROTTO_STATS.goldEarned = {}; GROTTO_STATS.dmgTaken = {}; GROTTO_STATS.xpEarned = {}; updateGrottoStats(); location.reload(); }); // Insert the button after the target element buildingDescElement.appendChild(button); } function initiateGrottoStats(){ if (!GROTTO_STATS.goldEarned || !GROTTO_STATS.dmgTaken || !GROTTO_STATS.xpEarned) { GROTTO_STATS.goldEarned = {}; GROTTO_STATS.dmgTaken = {}; GROTTO_STATS.xpEarned = {}; updateGrottoStats(); } } function addAutoGrottoButton() { // make sure the variable is defined if (!Array.isArray(CHARACTER.autoGrotto)) { CHARACTER.autoGrotto = [false, false, false]; updateCharacter(); } // instantiate the variable for grotto stats if it isn't already initiateGrottoStats(); for (let difficulty = 0; difficulty < 3; difficulty++) { //const target = $(`table.noBackground form.clearfix div input`)[index]; const grottoButton = document.querySelectorAll('table.noBackground form.clearfix div input')[difficulty]; if (!grottoButton) return; grottoButton.addEventListener('click', (event) => { CHARACTER.lastGrottoClick = difficulty; updateCharacter(); }); // Create the button const button = document.createElement("button"); if(CHARACTER.autoGrotto[difficulty]){ button.textContent = "Auto : ON"; button.className = "btn-small left btn-autoGrotto premiumButton"; } else { button.textContent = "Auto : OFF"; button.className = "btn-small left btn-autoGrotto"; } button.style.margin = "10px"; button.style.padding = "0 0 5px"; // Add a click event listener button.addEventListener("click", function (event) { event.preventDefault(); // Prevent default button behavior if(!CHARACTER.autoGrotto[difficulty] && isReadyForGrotto(difficulty)){ grottoSetAllButtonsToOFF(); CHARACTER.autoGrotto[difficulty] = true; updateCharacter(); button.textContent = "Auto : ON"; button.className = "btn-small left btn-autoGrotto premiumButton"; document.querySelectorAll('table.noBackground form.clearfix div input')[difficulty].click(); } else { CHARACTER.autoGrotto[difficulty] = false; updateCharacter(); button.textContent = "Auto : OFF"; button.className = "btn-small left btn-autoGrotto"; } //console.log(`CHARACTER.autoGrotto[${index}] is now `, CHARACTER.autoGrotto); }); // Insert the button after the target element grottoButton.parentNode.insertBefore(button, grottoButton.nextSibling); displayStatsAverage(difficulty); } } function grottoSetAllButtonsToOFF(){ CHARACTER.autoGrotto[0] = false; CHARACTER.autoGrotto[1] = false; CHARACTER.autoGrotto[2] = false; const buttons = document.querySelectorAll('.btn-autoGrotto'); buttons.forEach(button => { button.textContent = 'Auto : OFF'; button.className = "btn-small left btn-autoGrotto"; }); } function autoFightGrotto() { if(!CHARACTER.autoGrotto[0] && !CHARACTER.autoGrotto[1] && !CHARACTER.autoGrotto[2]) return; const randomDelay = Math.random() * 1000 + 200; console.log(`Action will be executed after ${randomDelay.toFixed(0)}ms`); // Set the timeout setTimeout(() => { if(!isReadyForGrotto()){ grottoSetAllButtonsToOFF(); updateCharacter(); } else { if(CHARACTER.autoGrotto[0])document.querySelectorAll('table.noBackground form.clearfix div input')[0].click(); if(CHARACTER.autoGrotto[1])document.querySelectorAll('table.noBackground form.clearfix div input')[1].click(); if(CHARACTER.autoGrotto[2])document.querySelectorAll('table.noBackground form.clearfix div input')[2].click(); } }, randomDelay); } function isReadyForGrotto(difficulty) { //en cas d'abscence de données, on combat si plus de 9000 HP if (!GROTTO_STATS.dmgTaken[difficulty] || GROTTO_STATS.dmgTaken[difficulty].length < 1) return (calculateCurrentHealth() > 9000 && CHARACTER.energy > 0); // sinon, on chope les plus gros dégats qu'on s'est mangé dans cette difficulté, et on y ajoute 10% let highestValue = 0; for (let value of GROTTO_STATS.dmgTaken[difficulty]) { if (value > highestValue) { highestValue = value; } } console.log("gros degats : "+(highestValue*1.1)); return (calculateCurrentHealth() > (highestValue*1.1) && CHARACTER.energy > 0); } function saveGrottoStats(grottoDifficulty){ const rewards = document.getElementsByClassName("gold")[1].textContent.split("\n")[1].split("+"); const goldEarned = parseInt(rewards[0].replace(/\D/g, '')); const xpEarned = parseInt(rewards[1].replace(/\D/g, '')); // Ensure the goldEarned array for the selected difficulty exists if (!GROTTO_STATS.goldEarned[grottoDifficulty]) { GROTTO_STATS.goldEarned[grottoDifficulty] = []; } // Push the new gold earned value into the array GROTTO_STATS.goldEarned[grottoDifficulty].push(goldEarned); // Keep only the last 20 entries for each difficulty if (GROTTO_STATS.goldEarned[grottoDifficulty].length > 20) { GROTTO_STATS.goldEarned[grottoDifficulty].shift(); // Remove the oldest entry } // Ensure the dmgTaken array for the selected difficulty exists if (!GROTTO_STATS.dmgTaken[grottoDifficulty]) { GROTTO_STATS.dmgTaken[grottoDifficulty] = []; } // Push the new dmg taken value into the array GROTTO_STATS.dmgTaken[grottoDifficulty].push(getGrottoHealthDamage(goldEarned)); // Keep only the last 20 entries for each difficulty if (GROTTO_STATS.dmgTaken[grottoDifficulty].length > 20) { GROTTO_STATS.dmgTaken[grottoDifficulty].shift(); // Remove the oldest entry } // Ensure the xpEarned array for the selected difficulty exists if (!GROTTO_STATS.xpEarned[grottoDifficulty]) { GROTTO_STATS.xpEarned[grottoDifficulty] = []; } // Push the new dmg taken value into the array GROTTO_STATS.xpEarned[grottoDifficulty].push(xpEarned); // Keep only the last 20 entries for each difficulty if (GROTTO_STATS.xpEarned[grottoDifficulty].length > 20) { GROTTO_STATS.xpEarned[grottoDifficulty].shift(); // Remove the oldest entry } // Update the grotto data with the new stats CHARACTER.lastGrottoClick = -1; updateGrottoStats(); updateCharacter(); } // This function calculates the average gold for a given difficulty function calculateGoldAverage(grottoDifficulty) { if (!GROTTO_STATS.goldEarned[grottoDifficulty] || GROTTO_STATS.goldEarned[grottoDifficulty].length < 1) return 0; let totalGold = 0; // Loop through the gold history for the given difficulty for (let i = 0; i < GROTTO_STATS.goldEarned[grottoDifficulty].length; i++) { totalGold += GROTTO_STATS.goldEarned[grottoDifficulty][i]; } return totalGold / GROTTO_STATS.goldEarned[grottoDifficulty].length; } function calculateDamageAverage(grottoDifficulty) { if (!GROTTO_STATS.dmgTaken[grottoDifficulty] || GROTTO_STATS.dmgTaken[grottoDifficulty].length < 1) return 0; let totalDmg = 0; // Loop through the gold history for the given difficulty for (let i = 0; i < GROTTO_STATS.dmgTaken[grottoDifficulty].length; i++) { totalDmg += GROTTO_STATS.dmgTaken[grottoDifficulty][i]; } return totalDmg / GROTTO_STATS.dmgTaken[grottoDifficulty].length; } function calculateXPAverage(grottoDifficulty) { if (!GROTTO_STATS.xpEarned[grottoDifficulty] || GROTTO_STATS.xpEarned[grottoDifficulty].length < 1) return 0; let totalGold = 0; // Loop through the gold history for the given difficulty for (let i = 0; i < GROTTO_STATS.xpEarned[grottoDifficulty].length; i++) { totalGold += GROTTO_STATS.xpEarned[grottoDifficulty][i]; } return totalGold / GROTTO_STATS.xpEarned[grottoDifficulty].length; } function calculateWinrate(grottoDifficulty) { if (!GROTTO_STATS.goldEarned[grottoDifficulty] || GROTTO_STATS.goldEarned[grottoDifficulty].length < 1) return 0; let totalwin = 0; // Loop through the gold history for the given difficulty for (let i = 0; i < GROTTO_STATS.goldEarned[grottoDifficulty].length; i++) { if(GROTTO_STATS.goldEarned[grottoDifficulty][i] > 0)totalwin += 1; } return (totalwin / GROTTO_STATS.goldEarned[grottoDifficulty].length * 100); } // Function to display the average gold under each button function displayStatsAverage(grottoDifficulty) { //console.log("Average gold for difficult "+grottoDifficulty+" : "+calculateGoldAverage(grottoDifficulty)); const button = document.querySelectorAll('.btn-autoGrotto')[grottoDifficulty]; if (!button) return; let avgGoldText = `${calculateGoldAverage(grottoDifficulty).toFixed(0).replace(/\B(?=(\d{3})+(?!\d))/g, '.')} `; let avgDmg = `${calculateDamageAverage(grottoDifficulty).toFixed(0).replace(/\B(?=(\d{3})+(?!\d))/g, '.')} `; let avgXP = `${calculateXPAverage(grottoDifficulty).toFixed(0).replace(/\B(?=(\d{3})+(?!\d))/g, '.')} `; let winrate = `${calculateWinrate(grottoDifficulty).toFixed(0)}% `; // Check if the display already exists, and update or create a new one let avgElement = button.querySelector('.gold-average'); avgElement = document.createElement('div'); avgElement.classList.add('gold-average'); avgElement.style.fontSize = '15px'; avgElement.style.marginLeft = '10px'; avgElement.style.textAlign = 'center'; // Center the text avgElement.style.display = 'block'; // Make sure it takes up the full width and goes below the button avgElement.style.width = '160px'; avgElement.style.textShadow = "0 0 4px #FF0000"; avgElement.style.fontFamily = 'monospace'; avgElement.style.fontWeight = 'bold'; avgElement.style.color = 'white'; avgElement.style.lineHeight = '25px'; button.parentNode.insertBefore(avgElement, button.nextSibling); avgElement.textContent = avgGoldText; // Create an image element and append it after the text let imgGold = document.createElement('img'); imgGold.src = '/img/symbols/res2.gif'; avgElement.appendChild(imgGold); imgGold.align = 'absmiddle'; // xp earned var lineBreak2 = document.createElement('br'); avgElement.appendChild(lineBreak2); var avgXPText = document.createTextNode(avgXP); avgElement.appendChild(avgXPText); let imgXP = document.createElement('img'); imgXP.src = '/img/symbols/level.gif'; avgElement.appendChild(imgXP); imgXP.align = 'absmiddle'; // health lost var lineBreak = document.createElement('br'); avgElement.appendChild(lineBreak); var avgDmgText = document.createTextNode(avgDmg); avgElement.appendChild(avgDmgText); let imgHealth = document.createElement('img'); imgHealth.src = '/img/symbols/herz.png'; avgElement.appendChild(imgHealth); imgHealth.align = 'absmiddle'; // winrate var lineBreak3 = document.createElement('br'); avgElement.appendChild(lineBreak3); var winrateText = document.createTextNode(winrate); avgElement.appendChild(winrateText); let imgWin = document.createElement('img'); imgWin.src = '/img/symbols/fightvalue.gif'; avgElement.appendChild(imgWin); imgWin.align = 'absmiddle'; } // if gold earned = 0, then it's lost,and the dmg taken is on left and not on right function getGrottoHealthDamage(goldEarned){ var win = 1; if(goldEarned == 0){ win = 0; } const wholeText = document.querySelectorAll('#reportResult div.wrap-left div.wrap-content p')[0].textContent; const extractedText = wholeText.match(/\(([^)]+)\)/)[1]; // Regular expression to match content between parentheses const numbers = extractedText.split(":"); return(parseInt(numbers[win])); } })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址